反射是 Java 動態性的基石,框架 (Spring、Hibernate、MyBatis) 的靈魂。掌握反射,即掌握「運行時分析類結構、操作對象」的能力。
// 1. 類字面常量 (編譯期已知,無初始化)
Class<String> clazz1 = String.class;
// 2. 實例 getClass() (運行期對象)
String s = "hello";
Class<?> clazz2 = s.getClass();
// 3. 類全限定名 (最常用,配置驅動)
Class<?> clazz3 = Class.forName("java.lang.String"); // 會觸發類初始化
// Class.forName(name, false, classLoader) 可控制是否初始化
// 無參構造器
Object obj = clazz.getDeclaredConstructor().newInstance();
// 有參構造器
Constructor<User> ctor = clazz.getDeclaredConstructor(String.class, int.class);
ctor.setAccessible(true); // 破壞私有構造器
User user = ctor.newInstance("張三", 25);
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.setAccessible(true);
Object result = method.invoke(user, "World"); // 實例方法需傳實例
// 靜態方法 invoke(null, args)
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(user, "李四"); // 設置值
String val = (String) field.get(user); // 獲取值
int[].class == int[].class,多維數組類型不同 ([[I vs [I)。Object[],需用 Array.set/get 或流式轉換。Type / ParameterizedType 獲取字段/方法簽名上的泛型參數 (如 MyBatis Mapper 接口解析)。| 場景 | 反射應用 |
|---|---|
| 配置文件加載 | clazz.getResourceAsStream("/config.properties") 類加載器加載 classpath 資源 | 註解掃描 | clazz.getAnnotations()、method.getAnnotation(Transactional.class) 實現 AOP 切點 |
| JSON 序列化 | 遍歷字段 getDeclaredFields() 獲取名值對,處理私有字段需 setAccessible |
| 動態代理 | Proxy.newProxyInstance() + InvocationHandler 實現 Spring AOP/事務 |
| 插件熱加載 | 自定義 ClassLoader 加載外部 JAR,反射實例化插件入口類 |
Method/Field/Constructor 對象,或用 MethodHandle / VarHandle (Java 9+)。setAccessible(true) 破壞封裝,模塊化 (JPMS) 環境下可能被拒絕。請最小化使用範圍。Class 對象阻止類卸載,自定義類加載器場景需謹慎。反射是把雙刃劍:框架開發必備利器,業務代碼慎用。理解其本質是「以運行期性能換取編譯期靈活性」,方能駕馭自如。