java.lang.reflect.Field 與 Method 是 Java 反射 API 的核心,提供了在執行期檢查、修改類別結構與動態呼叫的能力。本文詳細解析兩者關鍵方法、泛型型別處理、存取控制繞過、效能考量與典型應用場景。
| 方法 | 說明 |
|---|---|
getType() | 回傳欄位宣告型別的 Class 物件(原始型別回傳對應基本型別 Class)。 |
getGenericType() | 回傳精確泛型型別(Type),如 List 回傳 ParameterizedType。 |
get(Object obj) | 讀取指定物件上該欄位值,基本型別自動裝箱。 |
set(Object obj, Object value) | 設定指定物件上該欄位值,基本型別自動拆箱。 |
getXxx(Object obj) / setXxx(Object obj, xxx val) | 針對基本型別的專用方法(如 getInt, setBoolean),避免裝箱開銷。 |
setAccessible(true) | 關閉存取檢查,可讀寫 private、protected 欄位。 |
isEnumConstant() | 判斷是否為列舉常數。 |
getAnnotations() | 取得欄位上的註解(實作 AnnotatedElement)。 |
Class。List → List.class;型別變數 T → 擦除邊界(預設 Object.class)。Type 介面實例(ParameterizedType, TypeVariable, GenericArrayType, WildcardType)。public static void printField(Object target, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true); // 繞過 private
Object value = field.get(target);
System.out.println(fieldName + " = " + value);
}
public static void setField(Object target, String fieldName, Object newValue)
throws NoSuchFieldException, IllegalAccessException {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target, newValue);
}
final 欄位 set 會拋出 IllegalAccessException。setAccessible(true),在反序列化等特定場景下可修改。final 常數(static final 基本型別/字串),JVM 會內聯優化,修改不可見且行為未定義。| 方法 | 說明 |
|---|---|
getReturnType() / getGenericReturnType() | 回傳型別(Class/Type),void 回傳 void.class。 |
getParameterTypes() / getGenericParameterTypes() | 參數型別陣列,順序與宣告一致。 |
getExceptionTypes() / getGenericExceptionTypes() | 拋出的檢查型異常型別陣列。 |
invoke(Object obj, Object... args) | 動態呼叫方法。obj 為接收者(靜態方法傳 null),args 需與參數列表匹配(基本型別自動裝箱)。 |
isVarArgs() | 判斷是否為可變參數方法。 |
isBridge() | 判斷是否為編譯器產生的橋接方法(泛型擦除產物)。 |
getParameterAnnotations() | 取得參數上的註解陣列。 |
getDefaultValue() | 若方法為註解元素,回傳預設值。 |
getTypeParameters() | 回傳泛型方法的型別參數(TypeVariable[])。 |
invoke(obj, "arg1", new String[]{"a","b"}))。IllegalAccessException:存取權限不足(未 setAccessible)。IllegalArgumentException:參數數量/型別不匹配、接收者型別錯誤。NullPointerException:非靜態方法傳 null 接收者。InvocationTargetException:底層方法拋出的異常被包裹,真實異常在 getCause() 中。ExceptionInInitializerError:靜態方法觸發類別初始化失敗。// 等同於 str.indexOf(".", 8)
public static int dynamicIndexOf(String str, String substr, int fromIndex) {
try {
Method m = String.class.getMethod("indexOf", String.class, int.class);
return (Integer) m.invoke(str, substr, fromIndex);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
} catch (ReflectiveOperationException e) {
throw new IllegalStateException(e);
}
}
get/set/invoke 皆檢查權限,setAccessible(true) 可關閉(但需 ReflectPermission)。getDeclaredMethod 需遍歷方法表,建議快取 反射物件。Method/Field 至 Map 或陣列。MethodHandle (Java 7+) 或 VarHandle (Java 9+),效能接近直接呼叫。private 狀態,破壞類別不變條件。suppressAccessChecks 權限。Field 與 Method 賦予 Java 強大的動態性,是框架級開發的基石。業務代碼應極力避免直接使用反射,優先採用介面、多型、設計模式解決問題。必須使用時,請快取反射物件、處理好 InvocationTargetException、評估效能影響、並在安全審查中納入考量。