你是否好奇過 IDE 如何列出類的所有私有字段與方法?或是 JAR 套件中的類別資訊是如何被讀取的?答案皆在於 Java 的反射機制。本文將從核心概念出發,透過完整代碼示例,帶你掌握反射的動態發現、實例創建、字段操作與方法調用,並探討其在實際開發中的應用場景與效能考量。
反射是 Java 提供的一種強大機制,允許程式在運行時動態地發現、檢查並操作類別的結構(類、介面、字段、方法、建構子等),甚至能實例化物件、調用方法、讀寫字段。這打破了編譯時期的靜態綁定,賦予了框架開發(如 Spring、Hibernate)極大的靈活性。
反射相關類別主要位於 java.lang.reflect 套件,核心類別包括 Class、Constructor、Field、Method。以下以一個 Product 類為例,示範如何列出其完整結構:
package ria;
public class Product {
private String description;
private long id;
private String name;
private double price;
// 省略 Getter/Setter
}
編寫工具類 ReflectionUtil 來解析任意物件:
package ria;
import java.lang.reflect.*;
public class ReflectionUtil {
public static void describeInstance(Object object) {
Class<?> clazz = object.getClass();
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
Field[] fields = clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();
System.out.println("=== 類別: " + clazz.getName() + " ===");
System.out.println("建構子數量: " + constructors.length);
System.out.println("字段數量: " + fields.length);
System.out.println("方法數量: " + methods.length);
// 詳細列印建構子
for (Constructor<?> c : constructors) System.out.println(" 建構子: " + c);
// 詳細列印字段(含私有)
for (Field f : fields) System.out.println(" 字段: " + f);
// 詳細列印方法
for (Method m : methods) System.out.println(" 方法: " + m);
}
}
關鍵點:getDeclaredFields() 可獲取當前類別聲明的所有字段(含 private),而 getFields() 僅返回 public 字段(含繼承)。同理適用於方法與建構子。
反射允許通過 field.setAccessible(true) 繞過訪問控制。以下代碼示範如何動態讀取與修改物件的私有字段值:
// 讀取字段值
field.setAccessible(true);
Object value = field.get(object);
// 修改字段值
field.set(object, newValue);
進階技巧:遞歸向上查找父類字段,解決繼承層級中私有字段無法直接獲取的問題。
反射不僅能「看」,更能「做」。通過 Constructor.newInstance() 動態創建物件,通過 Method.invoke() 動態調用方法:
// 動態創建帶參數建構子的實例
Class<?>[] paramTypes = {int.class, int.class, int.class, int.class};
Object[] args = {1, 2, 100, 200};
Rectangle rect = (Rectangle) clazz.getConstructor(paramTypes).newInstance(args);
// 動態調用無參方法
Method method = clazz.getDeclaredMethod("doNothing");
method.setAccessible(true);
method.invoke(object);
利用反射實現一個「通用搜尋邏輯」,無需每個類別實作介面,即可根據字段值匹配條件:
public static boolean search(Object obj, String criteria) {
List<Field> fields = getAllDeclaredFields(obj.getClass()); // 含繼承字段
for (Field f : fields) {
f.setAccessible(true);
if (String.valueOf(f.get(obj)).equalsIgnoreCase(criteria)) return true;
}
return false;
}
此模式廣泛應用於框架的序列化、ORM 映射、配置綁定等場景。
Field/Method 對象。建議:僅在框架開發、動態代理、插件系統等「不得不用」的場景使用;業務邏輯優先使用多態、介面等靜態類型機制。
Java 反射是雙刃劍:它賦予了極致的動態能力,支撐了現代框架生態的基石;但濫用會帶來效能、安全與維護的隱患。理解其原理、掌握核心 API、權衡利弊,方能在架構設計中遊刃有餘。