反射 是 Java 動態語言特性的基石,允許程式在執行期檢查、修改類結構、建立實例、呼叫方法、存取欄位。本文系統整理反射核心 API、三種取得 Class 方式、物件建立、欄位/方法/建構子操作、權限繞過、泛型擦除下的 Type 機制,並給出實戰範例。
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
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 給反射存取套件 |
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 解析、效能優化策略,能讓你輕鬆閱讀主流框架源碼、建立靈活可擴充的系統架構。