| 維度 | RTTI | 反射 |
| .class 文件可用性 | 編譯期可用 | 編譯期不可用(運行時才加載) |
| 典型場景 | 已知類層次、編譯期可依賴 | 插件系統、遠程調用、序列化、IDE、框架容器 |
| 核心 API | Class, instanceof | Class, Method, Field, Constructor, Annotation |
反射核心能力
- 動態獲取類的所有方法/字段/構造器/註解(
getDeclaredMethods() 等)。
- 運行時創建對象(
constructor.newInstance())、調用方法(method.invoke(obj, args))、讀寫字段(field.get/set(obj))。
- 繞過訪問控制(
setAccessible(true)),慎用(破壞封裝、安全風險、性能損耗)。
方法提取器示例
public static void printMethods(Class> clazz) {
for (Method m : clazz.getDeclaredMethods()) {
System.out.println(m.getReturnType().getSimpleName() + " " + m.getName() +
Arrays.toString(m.getParameterTypes()));
}
}
動態代理:AOP 基石
java.lang.reflect.Proxy + InvocationHandler 創建接口的動態實現類。
- 所有方法調用委派給單一
invoke(proxy, method, args),實現橫切關注點(事務、日誌、權限、緩存)與業務邏輯分離。
- 構造器通常傳入「真實對象」引用,代理內部決定:前置處理 → 調用真實對象 → 後置處理 → 返回。
動態代理模板
public 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("[Before] " + method.getName());
Object result = method.invoke(target, args);
System.out.println("[After] " + method.getName());
return result;
}
}
// 使用
UserService real = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LoggingHandler(real)
);
proxy.saveUser(new User()); // 觸發代理邏輯
空對象模式:消除 null 檢查
- 定義實現接口的
NullObject,方法返回中性值(空集合、0、false、空字符串),不拋 NPE。
- 適用於「更接近數據層」的領域實體,避免調用鏈層層
if (obj != null)。
- 通常為單例:
static final User ANONYMOUS = new NullUser();。
- 配合動態代理可自動生成任意接口的空對象實現。
空對象 vs Mock/Stub
| 模式 | 目的 | 行為 |
| Null Object | 替代 null,提供安全默認行為 | 返回中性值,不拋異常 |
| Stub | 測試替身,返回預設數據 | 硬編碼返回值 |
| Mock | 測試替身,驗證交互 | 記錄調用、斷言參數/次序 |
接口與類型信息
接口是類型信息的「純粹形式」——無實現細節,僅定義契約。反射結合接口,構建了 Java 生態中極其強大的框架基礎設施:依賴注入容器、ORM 映射、序列化引擎、RPC 框架、測試 Mock 庫。
總結
第 14 章揭示了 Java「運行時不擦除類型信息」的設計哲學:Class 對象是元數據入口,RTTI 解決已知類型的動態分派,反射解決未知類型的動態操作,動態代理實現橫切邏輯解耦,空對象模式消除防衛性編程。掌握這些機制,不僅能讀懂 Spring/MyBatis 核心源碼,更能在架構設計中靈活運用動態特性,構建可擴展、低耦合的系統。
- 上一篇文章: Java 線程池核心原理與實戰指南(上):架構、參數、任務提交與 CompletionService
- 下一篇文章: Java ZXing 生成二維碼與條碼完整實戰:核心工具類、Logo 嵌入、Servlet 輸出
Copyright ©
程式碼之家 All Rights Reserved