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

Java 反射實戰:運行時動態訪問與修改對象私有字段完整指南

     編輯:Java 程式設計入門

反射三大核心類速覽

類作用常用方法
Class<?>類的運行時元數據入口getFields()、getDeclaredFields()、newInstance()
Field代表類的成員變量(含私有)setAccessible(true)、get(obj)、set(obj, val)
Method代表類的方法invoke(obj, args...)

實驗對象:Book & Page

class Book {
    public String title;
    public int length = 0;
    public ArrayList<Page> pages = null;

    @Override public String toString() {
        return "Book:\n  title=" + title + "\n  length=" + length + "\n  pages=" + pages;
    }
}
class Page { @Override public String toString() { return "  page\n"; } }

場景 1:修改基本類型字段

Book book = new Book();
Class<?> clazz = book.getClass();
Field f = clazz.getField("length");           // 僅能獲取 public 字段
f.setInt(book, 9);                            // 直接按類型寫入
System.out.println(book);  // length=9

場景 2:批量修改所有 public 字段(按類型分發)

Book book = new Book();
for (Field f : book.getClass().getFields()) {
    f.setAccessible(true);  // 允許訪問私有/受保護(此處 public 可省略)
    if (f.getType() == String.class) {
        f.set(book, "格林童話");
    } else if (f.getType() == int.class) {
        f.set(book, 199);
    }
}
// 結果:title=格林童話, length=199

場景 3:動態構造泛型集合字段

挑戰:pages 是 ArrayList<Page>,運行時泛型擦除,但可通過 getGenericType() 獲取 ParameterizedType 解析實際類型參數。

Book book = new Book();
Field f = book.getClass().getField("pages");
f.setAccessible(true);

// 1. 解析泛型類型:ArrayList → Page.class
ParameterizedType pt = (ParameterizedType) f.getGenericType();
Class<?> elementClass = (Class<?>) pt.getActualTypeArguments()[0];  // Page.class

// 2. 實例化元素並裝入 List
Object pageInstance = elementClass.getDeclaredConstructor().newInstance();
List<Object> list = new ArrayList<>();
list.add(pageInstance);

// 3. 寫入字段
f.set(book, list);
System.out.println(book);  // pages=[page]

關鍵技術點總結

  • getField vs getDeclaredField:前者含繼承的 public 字段,後者含本類所有字段(含私有),不含繼承。
  • setAccessible(true):暴力反射開關,繞過 Java 訪問檢查,慎用於生產代碼(模塊化系統可能拒絕)。
  • 泛型保留:字段、方法、構造器的泛型簽名在字節碼中保留,可通過 getGenericType() 獲取。
  • newInstance():調用無參構造器;若需帶參構造器,用 clazz.getConstructor(Types...).newInstance(args...)。

實際應用場景

  • 框架開發:ORM 自動映射結果集到 Bean、依賴注入容器掃描註解、序列化庫遍歷字段。
  • 測試工具:單元測試中設置私有狀態、Mock 靜態方法。
  • 熱加載/插件系統:動態加載類並實例化、調用擴充點方法。

性能與安全提示

  • 反射比直接調用慢 10~100 倍(JIT 難優化),熱點路徑請緩存 Field/Method 對象。
  • Java 9+ 模塊系統(JPMS)預設封裝內部包,需在 module-info.java 中 opens 或命令行 --add-opens。
  • 安全管理器環境下 setAccessible 可能拋出 InaccessibleObjectException。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved