Java 編譯產生 `.class` 字節碼文件,類加載器載入後,JVM 在方法區創建對應的 java.lang.Class<T> 實例。**反射就是通過這個 Class 對象,在運行時獲取類的完整定義(構造器、方法、字段、父類、介面、註解等)並動態操作。**
// 1. 編譯期已知類型:最常用、效能最好
Class<String> clazz1 = String.class;
// 2. 運行期字串類名:動態加載、插件系統、配置驅動
Class<?> clazz2 = Class.forName("java.lang.String"); // 拋出 ClassNotFoundException
// 3. 從實例獲取:通用物件處理
String str = "hello";
Class<?> clazz3 = str.getClass(); // 返回 String.class
Class<Person> clazz = Person.class;
// 獲取 public 構造器
Constructor<Person> ctor = clazz.getConstructor(String.class, int.class);
ctor.setAccessible(true); // 繞過訪問檢查,提升效能
Person p = ctor.newInstance("Alice", 25); // 等同 new Person("Alice", 25)
// 獲取所有構造器(含 private)
Constructor<?>[] ctors = clazz.getDeclaredConstructors();
// 獲取當前類聲明的所有方法(含 private,不含繼承)
Method[] declared = clazz.getDeclaredMethods();
// 獲取 public 方法(含繼承)
Method[] publicMethods = clazz.getMethods();
// 精確獲取:方法名 + 參數類型
Method toString = clazz.getDeclaredMethod("toString"); // 無參
Method setName = clazz.getDeclaredMethod("setName", String.class);
// 調用
toString.setAccessible(true);
String result = (String) toString.invoke(p); // p.toString()
setName.setAccessible(true);
setName.invoke(p, "Bob"); // p.setName("Bob")
// 靜態方法調用:第一參數傳 null
Method staticMethod = clazz.getDeclaredMethod("staticFactory");
staticMethod.invoke(null);
// 當前類聲明字段(含 private)
Field[] fields = clazz.getDeclaredFields();
// public 字段(含繼承)
Field[] publicFields = clazz.getFields();
// 精確獲取與操作
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
String name = (String) nameField.get(p); // 讀取
nameField.set(p, "Charlie"); // 寫入
// 靜態字段:第一參數傳 null
Field staticField = clazz.getDeclaredField("COUNT");
staticField.setAccessible(true);
int count = staticField.getInt(null);
// 父類
Class<?> superClazz = clazz.getSuperclass(); // Object.class
// 實現的介面
Class<?>[] interfaces = clazz.getInterfaces(); // [Serializable, Comparable...]
// 泛型資訊(進階)
Type genericSuper = clazz.getGenericSuperclass(); // ParameterizedType 等
interface Service { void execute(); }
class RealService implements Service {
public void execute() { System.out.println("真實業務"); }
}
class LoggingHandler implements InvocationHandler {
private final Object target;
public LoggingHandler(Object target) { this.target = target; }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置增強: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("後置增強: " + method.getName());
return result;
}
}
// 創建代理
Service real = new RealService();
Service proxy = (Service) Proxy.newProxyInstance(
Service.class.getClassLoader(),
new Class[] { Service.class },
new LoggingHandler(real)
);
proxy.execute();
// 輸出:
// 前置增強: execute
// 真實業務
// 後置增強: execute
// 依賴 cglib 依賴
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealService.class); // 繼承目標類
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB 前置");
Object result = proxy.invokeSuper(obj, args); // 調用父類方法
System.out.println("CGLIB 後置");
return result;
}
});
Service cglibProxy = (Service) enhancer.create();
cglibProxy.execute();
| 方面 | 影響 | 優化建議 |
|---|---|---|
| 訪問檢查 | `setAccessible(true)` 繞過,但需 `ReflectPermission` | 框架啟動時一次性設置,緩存 Member 對象 |
| 方法調用開銷 | 反射調用比直接調用慢 10-100 倍 | 熱點路徑用 MethodHandle、LambdaMetafactory 或代碼生成 |
| 泛型擦除 | 運行時無法獲取泛型實際類型 | 使用 TypeToken (Gson) 或保留簽名資訊 |
| 模塊化封裝 (JPMS) | Java 9+ 需 `opens` 導出包才能反射私有成員 | 模塊信息中聲明 `opens com.example to java.base` |
// MethodHandle:更底層、可內聯、支援簽名多態
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(String.class, "toUpperCase", MethodType.methodType(String.class));
String result = (String) mh.invokeExact("hello"); // "HELLO"
// VarHandle:字段/陣列元素的原子操作、內存排序控制
VarHandle handle = MethodHandles.lookup()
.in(AtomicReference.class)
.findVarHandle(AtomicReference.class, "value", Object.class);
// 等價於 AtomicReference.getAndSet() 等原子操作