反射是 Java 語言的一項核心特性,允許運行中的程序檢查、修改自身結構與行為。通過反射,我們可以在運行時動態獲取類的完整信息(構造器、方法、字段、註解等),並實例化對象、調用方法、訪問屬性,甚至繞過訪問控制修飾符。這為框架開發、依賴注入、動態代理等高級特性奠定了基礎。
java.lang.Class:反射的入口,每個類在 JVM 中只有一個 Class 實例。java.lang.reflect.Constructor:構造器信息與實例化操作。java.lang.reflect.Method:方法信息與調用操作。java.lang.reflect.Field:字段信息與讀寫操作。java.lang.reflect.Modifier:修飾符解析工具。// 1. 通過類字面量(編譯期已知類型)
Class<?> clazz1 = Person.class;
// 2. 通過對象實例(運行期獲取)
Person person = new Person();
Class<?> clazz2 = person.getClass();
// 3. 通過全限定類名動態加載(最靈活,支援配置驅動)
Class<?> clazz3 = Class.forName("com.example.Person");
Class<?> clazz = Class.forName("com.example.Person");
Person person = (Person) clazz.getDeclaredConstructor().newInstance();
// 等同於 clazz.newInstance()(已過時)
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true); // 允許訪問私有構造器
Person person = (Person) constructor.newInstance("張三", 25);
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.setAccessible(true);
Object result = method.invoke(person, "世界"); // 非靜態方法需傳入實例
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(person, "李四"); // 設置值
String name = (String) field.get(person); // 讀取值
// 獲取所有公共構造器
for (Constructor<?> c : clazz.getConstructors()) {
System.out.println("構造器: " + c);
for (Class<?> paramType : c.getParameterTypes()) {
System.out.println(" 參數類型: " + paramType.getName());
}
}
// 獲取所有聲明的方法(含私有)
for (Method m : clazz.getDeclaredMethods()) {
System.out.println("方法: " + Modifier.toString(m.getModifiers())
+ " " + m.getReturnType().getSimpleName()
+ " " + m.getName() + "()");
}
通過 Type 接口及其子類型 ParameterizedType,可在運行時獲取泛型實際類型參數。
public class ReflectionFactory {
public static <T> T createInstance(String className, Class<T> interfaceType) {
try {
Class<?> clazz = Class.forName(className);
return interfaceType.cast(clazz.getDeclaredConstructor().newInstance());
} catch (Exception e) {
throw new RuntimeException("實例化失敗: " + className, e);
}
}
}
// 配置文件指定實現類,無需修改工廠代碼即可擴展新實現
Fruit apple = ReflectionFactory.createInstance("com.example.Apple", Fruit.class);
JDK 動態代理基於接口,核心是 Proxy.newProxyInstance() 與 InvocationHandler,廣泛應用於 Spring AOP、RPC 框架等。
Method/Field/Constructor 對象。setAccessible(true) 可能受安全管理器限制,模塊化系統(JPMS)需在 module-info.java 中 opens 相關包。Java 反射是一把雙刃劍:它賦予了極大的靈活性,支撐了現代框架生態;但也帶來了性能開銷與安全風險。掌握反射的核心 API、理解類加載機制、遵循「配置驅動、約定優於配置」的設計原則,才能在實際項目中發揮其最大價值。