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

Java 基礎:反射機制核心 API 與實戰應用完整指南

     編輯:Java 相關知識

反射 是 Java 動態語言特性的基石,允許程式在執行期檢查、修改類結構、建立實例、呼叫方法、存取欄位。本文系統整理反射核心 API、三種取得 Class 方式、物件建立、欄位/方法/建構子操作、權限繞過、泛型擦除下的 Type 機制,並給出實戰範例。

一、反射核心價值

  • 解耦:編譯期不依賴具體類,執行期動態載入(插件架構、框架核心)
  • 通用處理:序列化、ORM、依賴注入、單元測試 Mock 皆仰賴反射
  • 除錯/診斷工具:動態列印物件結構、熱更新

二、取得 Class 物件的三種方式

// 1. 字串全限定名 - 最常用,支援動態配置
Class<?> c1 = Class.forName("com.example.Demo");

// 2. 類字面常量 - 編譯期型別安全
Class<Demo> c2 = Demo.class;

// 3. 物件 getClass() - 執行期已有實例
Class<? extends Demo> c3 = new Demo().getClass();

注意:同一個類在同一類載入器下只有一個 Class 實例,三種方式取得的是同一物件。

三、建立實例

// 呼叫無參建構子(必須存在且可存取)
Object obj = c1.newInstance();  // 已棄用 Java 9+

// 推薦:取得建構子再 newInstance
Constructor<Demo> cons = c1.getDeclaredConstructor();
Demo demo = cons.newInstance();

四、操作欄位

取得欄位

// 所有宣告欄位(含 private),不含繼承
Field[] fields = c1.getDeclaredFields();

// 特定欄位
Field nameField = c1.getDeclaredField("name");  // 找不到拋 NoSuchFieldException

讀寫欄位值

Field field = c1.getDeclaredField("privateField");
field.setAccessible(true);  // 關鍵:繞過 private 檢查

Demo demo = new Demo();
Object value = field.get(demo);      // 讀取
field.set(demo, "newValue");         // 寫入

// 靜態欄位傳 null
field.set(null, "staticValue");

五、操作方法

取得方法

Method[] methods = c1.getDeclaredMethods();           // 所有宣告方法
Method method = c1.getDeclaredMethod("methodName", String.class, int.class); // 精確簽名

呼叫方法

Method method = c1.getDeclaredMethod("sayHello", String.class);
method.setAccessible(true);
Object result = method.invoke(demo, "World");  // 實例方法傳實例;靜態方法傳 null

關鍵 Method API

  • getReturnType():回傳型別
  • getParameterTypes():參數型別陣列
  • getModifiers():修飾符位元遮罩

六、操作建構子

Constructor[] ctors = c1.getDeclaredConstructors();
Constructor<Demo> ctor = c1.getDeclaredConstructor(String.class, int.class);
ctor.setAccessible(true);
Demo demo = ctor.newInstance("name", 25);

七、setAccessible(true) 權限繞過機制

Java 安全管理員允許的前提下,AccessibleObject.setAccessible(true) 關閉語言層面的存取檢查,讓反射能操作 private 成員。框架(Spring、Hibernate)大量依賴此機制。

八、進階:泛型擦除下的 Type 系統

因泛型擦除,Field.getType() 只能得到原始型別。需用 Field.getGenericType() 取得 ParameterizedType 解析實際泛型參數。

Field listField = c1.getDeclaredField("stringList");
Type genericType = listField.getGenericType();
if (genericType instanceof ParameterizedType) {
    Type[] actualTypes = ((ParameterizedType) genericType).getActualTypeArguments();
    // actualTypes[0] == String.class
}

九、效能考量與最佳實踐

場景建議
高頻呼叫快取 Field/Method/Constructor 物件,避免重複查找
熱路徑考慮 MethodHandle(Java 7+)或字節碼生成庫 替代反射
安全敏感最小權限原則,僅對必要成員 setAccessible
模組化 (Java 9+)需在 module-info.java 開放 opens 給反射存取套件

十、實戰範例:簡易物件轉 JSON 工具

public static String toJson(Object obj) throws Exception {
    Class<?> clazz = obj.getClass();
    StringBuilder sb = new StringBuilder("{");
    Field[] fields = clazz.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        Field f = fields[i];
        f.setAccessible(true);
        sb.append("\"").append(f.getName()).append("\":");
        Object val = f.get(obj);
        if (val instanceof String) sb.append("\"").append(val).append("\"");
        else sb.append(val);
        if (i < fields.length - 1) sb.append(",");
    }
    return sb.append("}").toString();
}

十一、總結

反射賦予 Java 動態性,是框架級開發的核心武器。掌握 Class、Field、Method、Constructor 四大核心 API、權限繞過、泛型 Type 解析、效能優化策略,能讓你輕鬆閱讀主流框架源碼、建立靈活可擴充的系統架構。

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