MyBatis封裝簡單的CRUD
MyBatis封裝簡單的CRUD
1)公共的Dao接口
import java.io.Serializable; import java.util.List;public interface IBaseDao<T extends BaseDO<T>, PK extends Serializable> { / 新增(不會將序列生成的ID,注入) 效率較save(T t)高 @param t / void create(T t); / 批量新增(不會將序列生成的ID,注入) 效率較saveOfBatch(List<T> tList)高 @param tList / void createOfBatch(List<T> tList); / 新增(會將序列生成的ID,注入) @param t */ void save(T t); / 批量新增(會將序列生成的ID,注入) @param tList / void saveOfBatch(List<T> tList); /** 根據ID進行刪除 @param id / void removeById(PK id); / 根據ids進行批量刪除 @param ids */ void removeOfBatch(List<PK> ids); void removeAll(); / 更新,字段為空,則不進行更新 @param t / void modify(T t); /** 批量更新 @param tList / void modifyOfBatch(List<T> tList); / 根據ID獲取對象 @param id @return / T findOneById(PK id); / 獲取所有的對象 @return / List<T> findAll(); /** 獲取記錄數 @return / Long findAllCount(); }</pre>
2)公共的Dao接口實現類
import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map;import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils; import org.mybatis.spring.SqlSessionTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository;
import com.msd.ass.commons.util.GenericsUtils; import com.msd.ass.commons.util.ReflectionUtils; import com.msd.ass.core.anno.base.Ignore; import com.msd.ass.core.anno.base.PrimaryKey; import com.msd.ass.core.anno.base.Table; import com.msd.ass.core.anno.base.TableColumn; import com.msd.ass.core.constant.AssConstant;
@Repository("BaseDao") public abstract class BaseDao<T extends BaseDO<T>, PK extends Serializable> implements IBaseDao<T, PK> { protected Logger logger = LoggerFactory .getLogger(this .getClass()); @Resource(name = "sqlSessionTemplateASS") public SqlSessionTemplate sqlSessionTemplateASS; private Class<T> entityClass; //實體類主鍵名稱 private String pkName; //實體類ID字段名稱 private String idName; //主鍵的序列 private String seq; private String tableName; / 作cache 結構{T類的鏡像,{數據庫列名,實體字段名}} / private static final Map<Class<?>, Map<String, String>> classFieldMap = new HashMap<Class<?>, Map<String, String>>(); private Map<String, String> currentColumnFieldNames; private SQLGenerator<T> sqlGenerator; / / @SuppressWarnings("unchecked") public BaseDao() { super(); this.entityClass = (Class<T>) GenericsUtils .getSuperClassGenricType(this.getClass()); currentColumnFieldNames = classFieldMap.get(entityClass); if (null == currentColumnFieldNames) { currentColumnFieldNames = new LinkedHashMap<String, String>(); classFieldMap.put(entityClass, currentColumnFieldNames); } // 作cache Field[] fields = this.entityClass.getDeclaredFields(); String fieldName = null; String columnName = null; for (Field field : fields) { if (field.isAnnotationPresent(Ignore.class)) { continue; } fieldName = field.getName(); TableColumn tableColumn = field.getAnnotation(TableColumn.class); if (null != tableColumn) { columnName = tableColumn.value(); } else { columnName = null; } // 如果未標識特殊的列名,默認取字段名 columnName = (StringUtils.isEmpty(columnName) ? StringUtils .upperCase(fieldName) : columnName); currentColumnFieldNames.put(columnName, fieldName); if (field.isAnnotationPresent(PrimaryKey.class)) { // 取得ID的列名 idName = fieldName; pkName = columnName; PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class); seq = primaryKey.seq(); } } Table table = this.entityClass.getAnnotation(Table.class); if (null == table) { throw new RuntimeException("類-" + this.entityClass + ",未用@Table注解標識!!"); } tableName = table.value(); sqlGenerator = new SQLGenerator<T>(currentColumnFieldNames.keySet(), tableName,pkName,seq); } @Override public void create(T t) { sqlSessionTemplateASS.insert("create", sqlGenerator.sql_create(t, currentColumnFieldNames)); } @Override public void createOfBatch(List<T> tList) { if(null == tList || tList.isEmpty()){ return; } int len = tList.size(), i = 0; List<T> temp = new ArrayList<T>(); //獲取列表的第一個對象的pk的value Object pkVal = null; for (; i < len; i++) { T t = tList.get(i); if(i==0){ pkVal = ReflectionUtils.invokeGetterMethod(t, idName); } temp.add(t); if (i > 0 && i % AssConstant.FLUSH_CRITICAL_VAL == 0) { sqlSessionTemplateASS.insert("createOfBatch", sqlGenerator .sql_createOfBatch(temp, currentColumnFieldNames,pkVal)); sqlSessionTemplateASS.flushStatements(); temp = new ArrayList<T>(); } } sqlSessionTemplateASS.insert("createOfBatch", sqlGenerator .sql_createOfBatch(temp, currentColumnFieldNames,pkVal)); } @Override public void save(T t) { if(StringUtils.isEmpty(seq)){ this.create(t); } logger.info("生成序列開始:----------start----------"); Long nextval = sqlSessionTemplateASS.selectOne("fetchSeqNextval","SELECT ".concat(seq).concat(" FROM DUAL")); ReflectionUtils.invokeSetterMethod(t, idName, nextval); logger.info("生成序列結束:---------- end ----------"); this.create(t); }
@Override public void saveOfBatch(List<T> tList) { if(null == tList || tList.isEmpty()){ return; } if(StringUtils.isEmpty(seq)){ this.createOfBatch(tList); } logger.info("生成序列開始:----------start----------"); for(T t : tList){ Long nextval = sqlSessionTemplateASS.selectOne("fetchSeqNextval","SELECT ".concat(seq).concat(" FROM DUAL")); ReflectionUtils.invokeSetterMethod(t, idName, nextval); } logger.info("生成序列結束:---------- end ----------"); this.createOfBatch(tList); }
@Override public void removeById(PK id) { sqlSessionTemplateASS.delete("removeById", sqlGenerator.sql_removeById(id)); } @Override public void removeOfBatch(List<PK> ids) { if(null == ids || ids.isEmpty()){ return; } int len = ids.size(), i = 0; List<PK> temp = new ArrayList<PK>(); for (; i < len; i++) { temp.add(ids.get(i)); if (i > 0 && i % AssConstant.FLUSH_CRITICAL_VAL == 0) { sqlSessionTemplateASS.delete("removeOfBatch", sqlGenerator.sql_removeOfBatch(temp)); sqlSessionTemplateASS.flushStatements(); temp = new ArrayList<PK>(); } } sqlSessionTemplateASS.delete("removeOfBatch", sqlGenerator.sql_removeOfBatch(temp)); } @Override public void removeAll(){ sqlSessionTemplateASS.delete("removeAll", sqlGenerator.sql_removeAll()); } @Override public void modify(T t) { sqlSessionTemplateASS.update("modify", sqlGenerator.sql_modify(t, currentColumnFieldNames)); } @Override public void modifyOfBatch(List<T> tList) { if(null == tList || tList.isEmpty()){ return; } int len = tList.size(),i=0; for(;i<len;i++){ this.modify(tList.get(i)); if (i > 0 && i % AssConstant.FLUSH_CRITICAL_VAL == 0) { sqlSessionTemplateASS.flushStatements(); } } } @Override public T findOneById(PK id) { Map<String, Object> resultMap = sqlSessionTemplateASS.selectOne( "findOneById", sqlGenerator.sql_findOneById(id)); return handleResult(resultMap, this.entityClass); } @Override public List<T> findAll() { List<Map<String, Object>> resultMapList = sqlSessionTemplateASS .selectList("findAll", sqlGenerator.sql_findAll()); List<T> tList = new ArrayList<T>(resultMapList.size()); for (Map<String, Object> resultMap : resultMapList) { T t = handleResult(resultMap, this.entityClass); tList.add(t); } return tList; } @Override public Long findAllCount() { Long count = sqlSessionTemplateASS .selectOne("findAllCount", sqlGenerator.sql_findAllCount()); return count; } private T handleResult(Map<String, Object> resultMap, Class<T> tClazz) { T t = null; try { t = tClazz.newInstance(); } catch (InstantiationException e) { logger.error("/**"); logger.error("封裝查詢結果時,實例化對象(" + this.entityClass + ")時,出現異常!" + e.getMessage()); logger.error("/**"); } catch (IllegalAccessException e) { logger.error("/**"); logger.error("封裝查詢結果時,實例化對象(" + this.entityClass + ")時,出現異常!" + e.getMessage()); logger.error("/**"); } for (Map.Entry<String, Object> entry : resultMap.entrySet()) { String key = entry.getKey(); key = currentColumnFieldNames.get(key); Object val = entry.getValue(); ReflectionUtils.invokeSetterMethod(t, key, val); } return t; } }</pre>
3)xml配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ";<mapper namespace="com.szy.ass.core.base.BaseDao"> <!-- 新增 --> <insert id="create"> ${value} </insert>
<!-- 批量新增 --> <insert id="createOfBatch"> ${value} </insert>
<!-- 根據ID刪除 --> <delete id="removeById"> ${value} </delete>
<!-- 批量刪除 --> <delete id="removeOfBatch"> ${value} </delete>
<!-- 批量刪除 --> <delete id="removeAll"> ${value} </delete>
<!-- 更新 --> <update id="modify">${value}</update> <!-- 根據ID查詢單個 --> <select id="findOneById" resultType="hashmap"> ${value} </select>
<!-- 查詢所有 --> <select id="findAll" resultType="hashmap"> ${value} </select>
<!-- 查詢總數量 --> <select id="findAllCount" resultType="Long"> ${value} </select> <!-- 獲取下一個序列的值 --> <select id="fetchSeqNextval" resultType="Long" flushCache="true"> ${value} </select> </mapper></pre>
4)兩個工具類
4.1)生成SQL的工具類
import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set;import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import com.msd.ass.commons.util.DateUtil; import com.msd.ass.commons.util.ReflectionUtils; import com.msd.ass.core.constant.AssConstant;
/ Description: 生成查詢數量的SQL / public class SQLGenerator<T> { protected Logger logger = LoggerFactory.getLogger(this.getClass()); private Set<String> columns; private String tableName; private String columnsStr; private String pkName; private String seq; public SQLGenerator(Set<String> columns, String tableName, String pkName, String seq) { super(); this.columns = columns; this.tableName = tableName; this.pkName = pkName; this.seq = seq; this.columnsStr = StringUtils.join(this.columns, ","); } / 生成新增的SQL @param t @param currentColumnFieldNames @return / public String sql_create(T t, Map<String, String> currentColumnFieldNames) { List<Object> values = obtainFieldValues(t, currentColumnFieldNames); StringBuilder sql_build = new StringBuilder(); sql_build.append("INSERT INTO ").append(tableName).append("(") .append(columnsStr).append(")values(") .append(StringUtils.join(values, ",")).append(")"); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } / 生成批量新增的SQL @param tList @param currentColumnFieldNames @return / public String sql_createOfBatch(List<T> tList, Map<String, String> currentColumnFieldNames,Object pkVal) { StringBuilder sql_build = new StringBuilder(); int len = tList.size(),i=0; if(StringUtils.isNotEmpty(seq) && null == pkVal){ // ID使用序列 sql_build.append("INSERT INTO ").append(tableName).append("(") .append(columnsStr).append(")"); sql_build.append(" SELECT ").append(seq).append(" , a.* FROM ( "); for (; i < len; i++) { T t = tList.get(i); List<Object> values = obtainFieldValues(t, currentColumnFieldNames); values.remove(seq); if (i == 0) { sql_build.append(" SELECT "); } else { sql_build.append(" UNION ALL SELECT "); } int j = 0, vlen = values.size(); for (; j < vlen; j++) { sql_build.append(values.get(j)).append(" AS T").append(j); if (j != (vlen - 1)) { sql_build.append(","); } } sql_build.append(" FROM DUAL "); } sql_build.append(" ) a "); } else { //ID沒有使用序列 sql_build.append("INSERT INTO ").append(tableName).append("(") .append(columnsStr).append(")"); for (; i < len; i++) { T t = tList.get(i); List<Object> values = obtainFieldValues(t, currentColumnFieldNames); if (i == 0) { sql_build.append(" SELECT "); } else { sql_build.append(" UNION ALL SELECT "); } sql_build.append(StringUtils.join(values, ",")).append( " FROM DUAL "); } } String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } / 提供給生成新增SQL 使用 @param t @param currentColumnFieldNames @return / private List<Object> obtainFieldValues(T t, Map<String, String> currentColumnFieldNames) { List<Object> values = new LinkedList<Object>(); for (String column : columns) { Object value = ReflectionUtils.obtainFieldValue(t, currentColumnFieldNames.get(column)); if(StringUtils.equalsIgnoreCase(column, pkName) && null == value){ value = seq; }else{ value = handleValue(value); } values.add(value); } return values; } / 處理value @param value @return */ private Object handleValue(Object value) { if (value instanceof String) { value = "\'" + value + "\'"; } else if (value instanceof Date) { Date date = (Date) value; String dateStr = DateUtil.convertDateToString(date, DateUtil.FULL_TIME_FORMAT); value = "TO_TIMESTAMP('" + dateStr + "','YYYY-MM-DD HH24:MI:SS.FF3')"; } else if (value instanceof Boolean) { Boolean v = (Boolean) value; value = v ? 1 : 0; }else if(null == value || StringUtils.isBlank(value.toString())){ value = "''"; } return value; } / 生成根據ID刪除的SQL @param id @return / public <PK> String sql_removeById(PK id) { StringBuilder sql_build = new StringBuilder(); sql_build.append("DELETE FROM ").append(this.tableName) .append(" WHERE ").append(pkName).append(" = ").append(id); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } /** 生成根據IDs批量刪除的SQL @param ids @return / public <PK> String sql_removeOfBatch(List<PK> ids) { StringBuilder sql_build = new StringBuilder(); sql_build.append("DELETE FROM ").append(this.tableName) .append(" WHERE ").append(pkName).append(" IN ( 0 "); int len = ids.size(), i = 0; for (; i < len; i++) { PK id = ids.get(i); sql_build.append(",").append(id); if (i > 0 && i % (AssConstant.DELETE_CRITICAL_VAL - 1) == 0) { sql_build.append(")").append(" OR ").append(pkName) .append(" IN ( 0 "); } } sql_build.append(")"); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } public String sql_removeAll() { StringBuilder sql_build = new StringBuilder(); sql_build.append("DELETE FROM ").append(this.tableName); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } / 生成更新的SQL @param t @param currentColumnFieldNames @return / public String sql_modify(T t, Map<String, String> currentColumnFieldNames) { List<String> values = obtainColumnVals(t, currentColumnFieldNames); Object id = ReflectionUtils.obtainFieldValue(t, currentColumnFieldNames.get(pkName)); id = handleValue(id); StringBuilder sql_build = new StringBuilder(); sql_build.append("UPDATE ").append(tableName).append(" SET ") .append(StringUtils.join(values, ",")).append(" WHERE ") .append(pkName).append(" = ").append(id); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } / 提供給生成更新SQL使用 @param t @param currentColumnFieldNames @return / private List<String> obtainColumnVals(T t, Map<String, String> currentColumnFieldNames) { List<String> colVals = new LinkedList<String>(); for (String column : columns) { Object value = ReflectionUtils.obtainFieldValue(t, currentColumnFieldNames.get(column)); if (value != null && !StringUtils.equalsIgnoreCase(column, pkName)) { colVals.add(column + "=" + handleValue(value)); } } return colVals; } / 生成根據ID查詢的SQL @param id @return */ public <PK> String sql_findOneById(PK id) { StringBuilder sql_build = new StringBuilder(); sql_build.append("SELECT ").append(columnsStr).append(" FROM ") .append(this.tableName) .append(" WHERE ROWNUM = 1 AND " + pkName + " = " + id); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } / 生成查詢所有的SQL @return / public String sql_findAll() { StringBuilder sql_build = new StringBuilder(); sql_build.append("SELECT ").append(columnsStr).append(" FROM ") .append(this.tableName); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } /* 生成查詢數量的SQL @return */ public String sql_findAllCount() { StringBuilder sql_build = new StringBuilder(); sql_build.append("SELECT COUNT(1) ").append(" FROM ") .append(this.tableName); String sql = sql_build.toString(); logger.debug("生成的SQL為: " + sql); return sql; } }</pre>
4.1)反射的工具類
import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Timestamp; import java.text.ParseException; import java.util.Date; import java.util.HashMap; import java.util.Map;import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory;
/ Description:反射工具類 / public abstract class ReflectionUtils { private static final Logger logger = LoggerFactory .getLogger(ReflectionUtils.class); / 緩存方法 / private static final Map<Class<?>, Method[]> METHODS_CACHEMAP = new HashMap<Class<?>, Method[]>(); / 反射 取值、設值,合并兩個對象(Field same only ) @param from @param to */ public static <T> void copyProperties(T fromobj, T toobj, String... fieldspec) { for (String filename : fieldspec) { Object val = ReflectionUtils.invokeGetterMethod(fromobj, filename); ReflectionUtils.invokeSetterMethod(toobj, filename, val); } } / 調用Getter方法 @param obj 對象 @param propertyName 屬性名 @return / public static Object invokeGetterMethod(Object obj, String propertyName) { String getterMethodName = "get" + StringUtils.capitalize(propertyName); return invokeMethod(obj, getterMethodName, null, null); } / 調用Setter方法,不指定參數的類型 @param obj @param propertyName @param value / public static void invokeSetterMethod(Object obj, String propertyName, Object value) { invokeSetterMethod(obj, propertyName, value, null); } / 調用Setter方法,指定參數的類型 @param obj @param propertyName 字段名 @param value @param propertyType 為空,則取value的Class / public static void invokeSetterMethod(Object obj, String propertyName, Object value, Class<?> propertyType) { value = handleValueType(obj,propertyName,value); propertyType = propertyType != null ? propertyType : value.getClass(); String setterMethodName = "set" + StringUtils.capitalize(propertyName); invokeMethod(obj, setterMethodName, new Class<?>[] { propertyType }, new Object[] { value }); } private static Object handleValueType(Object obj, String propertyName, Object value){ String getterMethodName = "get" + StringUtils.capitalize(propertyName); Class<?> argsType = value.getClass();; Class<?> returnType = obtainAccessibleMethod(obj, getterMethodName).getReturnType(); if(argsType == returnType){ return value; } if (returnType == Boolean.class) { String temp = value.toString(); value = (StringUtils.isNotBlank(temp) && Long.valueOf(temp) > 0) ? true : false; } else if (returnType == Long.class) { value = Long.valueOf(value.toString()); }else if(returnType == Date.class){ try { value = SimpleDateFormatFactory.getInstance(DateUtil.FULL_TIME_FORMAT).parse(value.toString()); } catch (ParseException e) { logger.error("類型轉型Timpestap-->Date時,發生錯誤! " + e.getMessage() + "("+value.toString()+")"); } } else if (returnType == Short.class) { value = Short.valueOf(value.toString()); } else if (returnType == BigDecimal.class) { value = BigDecimal.valueOf(Long.valueOf(value.toString())); } else if (returnType == BigInteger.class) { value = BigInteger.valueOf(Long.valueOf(value.toString())); } else if(returnType == String.class){ value = String.valueOf(value); }else if(returnType == Integer.class){ value = Integer.valueOf(value.toString()); } return value; } public static void main(String[] args) throws Exception { Timestamp ts = new Timestamp(System.currentTimeMillis()); System.out.println(SimpleDateFormatFactory.getInstance(DateUtil.FULL_TIME_FORMAT).parse(ts.toString())); } / 直接調用對象方法,忽視private/protected修飾符 @param obj @param methodName @param parameterTypes @param params @return / public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, final Object[] args) { Method method = obtainAccessibleMethod(obj, methodName, parameterTypes); if (method == null) { throw new IllegalArgumentException( "Devkit: Could not find method [" + methodName + "] on target [" + obj + "]."); } try { return method.invoke(obj, args); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } / 循環向上轉型,獲取對象的DeclaredMethod,并強制設置為可訪問 如向上轉型到Object仍無法找到,返回null 用于方法需要被多次調用的情況,先使用本函數先取得Method,然后調用Method.invoke(Object obj,Object... args) @param obj @param methodName @param parameterTypes @return / public static Method obtainAccessibleMethod(final Object obj, final String methodName, final Class<?>... parameterTypes) { Class<?> superClass = obj.getClass(); Class<Object> objClass = Object.class; for (; superClass != objClass; superClass = superClass.getSuperclass()) { Method method = null; try { method = superClass.getDeclaredMethod(methodName, parameterTypes); method.setAccessible(true); return method; } catch (NoSuchMethodException e) { // Method不在當前類定義,向上轉型 } catch (SecurityException e) { // Method不在當前類定義,向上轉型 } } return null; } / 不能確定方法是否包含參數時,通過方法名匹配獲得方法 @param obj @param methodName @return / public static Method obtainMethod(final Object obj, final String methodName) { Class<?> clazz = obj.getClass(); Method[] methods = METHODS_CACHEMAP.get(clazz); if (methods == null) { // 尚未緩存 methods = clazz.getDeclaredMethods(); METHODS_CACHEMAP.put(clazz, methods); } for (Method method : methods) { if (method.getName().equals(methodName)) return method; } return null; } / 直接讀取對象屬性值 忽視private/protected修飾符,不經過getter函數 @param obj @param fieldName @return / public static Object obtainFieldValue(final Object obj, final String fieldName) { Field field = obtainAccessibleField(obj, fieldName); if (field == null) { throw new IllegalArgumentException( "Devkit: could not find field [" + fieldName + "] on target [" + obj + "]"); } Object retval = null; try { retval = field.get(obj); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return retval; } / 直接設置對象屬性值 忽視private/protected修飾符,不經過setter函數 @param obj @param fieldName @param value / public static void setFieldValue(final Object obj, final String fieldName, final Object value) { Field field = obtainAccessibleField(obj, fieldName); if (field == null) { throw new IllegalArgumentException( "Devkit: could not find field [" + fieldName + "] on target [" + obj + "]"); } try { field.set(obj, value); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } / 循環向上轉型,獲取對象的DeclaredField,并強制設為可訪問 如向上轉型Object仍無法找到,返回null @param obj @param fieldName @return / public static Field obtainAccessibleField(final Object obj, final String fieldName) { Class<?> superClass = obj.getClass(); Class<Object> objClass = Object.class; for (; superClass != objClass; superClass = superClass.getSuperclass()) { try { Field field = superClass.getDeclaredField(fieldName); field.setAccessible(true); return field; } catch (NoSuchFieldException e) { // Field不在當前類定義,向上轉型 } catch (SecurityException e) { // Field不在當前類定義,向上轉型 } } return null; } }</pre>