首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 反射核心:Field 與 Method 類深度解析與實戰應用

     編輯:Java 相關知識

前言

java.lang.reflect.Field 與 Method 是 Java 反射 API 的核心,提供了在執行期檢查、修改類別結構與動態呼叫的能力。本文詳細解析兩者關鍵方法、泛型型別處理、存取控制繞過、效能考量與典型應用場景。

一、Field 類:動態存取欄位

1.1 核心方法速查

方法說明
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)。

1.2 型別系統:Class vs Type

  • getType():型別擦除後的 Class。List → List.class;型別變數 T → 擦除邊界(預設 Object.class)。
  • getGenericType():保留泛型資訊的 Type 介面實例(ParameterizedType, TypeVariable, GenericArrayType, WildcardType)。

1.3 讀寫範例

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);
}

1.4 final 欄位特殊規則

  • 一般情況下對 final 欄位 set 會拋出 IllegalAccessException。
  • 唯一例外:非靜態實例欄位,且已呼叫 setAccessible(true),在反序列化等特定場景下可修改。
  • 強烈不建議 修改 final 常數(static final 基本型別/字串),JVM 會內聯優化,修改不可見且行為未定義。

二、Method 類:動態呼叫方法

2.1 核心方法速查

方法說明
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[])。

2.2 invoke 關鍵規則與異常

  • 參數匹配:實參型別必須可賦值給形參型別(支援多態、基本型別自動裝箱、介面實作)。
  • 可變參數:呼叫時最後一個參數必須是陣列(invoke(obj, "arg1", new String[]{"a","b"}))。
  • 常見異常:
    • IllegalAccessException:存取權限不足(未 setAccessible)。
    • IllegalArgumentException:參數數量/型別不匹配、接收者型別錯誤。
    • NullPointerException:非靜態方法傳 null 接收者。
    • InvocationTargetException:底層方法拋出的異常被包裹,真實異常在 getCause() 中。
    • ExceptionInInitializerError:靜態方法觸發類別初始化失敗。

2.3 動態呼叫範例

// 等同於 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);
    }
}

三、效能與安全考量

3.1 效能開銷來源

  1. 存取檢查:每次 get/set/invoke 皆檢查權限,setAccessible(true) 可關閉(但需 ReflectPermission)。
  2. 裝箱/拆箱:基本型別參數/回傳值產生包裝物件。
  3. JIT 難以優化:反射呼叫為黑盒,難以內聯、逃逸分析。
  4. Method/Field 查找:getDeclaredMethod 需遍歷方法表,建議快取 反射物件。

3.2 優化策略

  • 啟動階段一次性解析並快取 Method/Field 至 Map 或陣列。
  • 熱點路徑改用 MethodHandle (Java 7+) 或 VarHandle (Java 9+),效能接近直接呼叫。
  • 大量物件屬性拷貝場景,考慮程式碼生成庫或編譯期註解處理器。

3.3 安全性風險

  • 繞過封裝修改 private 狀態,破壞類別不變條件。
  • 動態呼叫任意方法,若參數來自不可信輸入,可能導致任意代碼執行(RCE)。
  • 安全管理器可限制 suppressAccessChecks 權限。

四、典型應用場景

  1. 框架開發:Spring 依賴注入、MyBatis 結果映射、Hibernate 實體存取。
  2. 序列化/反序列化:Jackson、Gson、Protobuf 運行期解析結構。
  3. 測試與 Mock 工具:Mockito、PowerMock 繞過封裝驗證私有行為。
  4. 動態代理輔助:解析介面方法生成攔截邏輯。
  5. 配置綁定:將 YAML/Properties 映射至 POJO 欄位。
  6. 插件/熱插拔系統:動態載入類別並檢查契約方法。

五、總結

Field 與 Method 賦予 Java 強大的動態性,是框架級開發的基石。業務代碼應極力避免直接使用反射,優先採用介面、多型、設計模式解決問題。必須使用時,請快取反射物件、處理好 InvocationTargetException、評估效能影響、並在安全審查中納入考量。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved