RTTI (Run-Time Type Identification,運行時類型識別) 是 Java 實現多態的基礎。每個對象在運行時都攜帶類型信息,JVM 通過 Class 對象維護類的元數據,使得「向上轉型」後仍能正確調用實際類型的方法。
java.lang.Class 是「類的類」。每個類加載後,JVM 在堆中創建一個對應的 Class 對象,包含類的完整元數據。
// 1. 對象實例調用 getClass()
Human person = new Human();
Class> c1 = person.getClass();
// 2. 類字面量
Class> c2 = Human.class;
// 3. 字符串全限定名加載
Class> c3 = Class.forName("com.example.Human");
class Human {
public void say() { System.out.println("Human"); }
}
class Woman extends Human {
@Override public void say() { System.out.println("Woman"); }
}
public class Test {
public static void main(String[] args) {
Human h = new Woman(); // 向上轉型
System.out.println(h.getClass().getName()); // 輸出 "Woman"
h.say(); // 輸出 "Woman" - 動態分派
}
}
機制:h 的靜態類型是 Human,但 h.getClass() 返回實際類型 Woman。方法調用通過 Class 對象中的方法表動態分派,實現多態。
| 方法 | 功能 |
|---|---|
| getName() | 類全限定名 |
| getSimpleName() | 類簡單名 |
| getPackage() | 包對象 |
| getSuperclass() | 父類 Class |
| getInterfaces() | 實現的接口數組 |
| getModifiers() | 修飾符 (public/abstract 等) |
| newInstance() | 創建實例 (調用無參構造) |
| getFields() | 所有 public 字段 (含繼承) |
| getDeclaredFields() | 聲明的字段 (含私有、不含繼承) |
| getMethods() | 所有 public 方法 (含繼承) |
| getDeclaredMethods() | 聲明的方法 (含私有、不含繼承) |
| getConstructors() | public 構造器 |
| getDeclaredConstructors() | 聲明的構造器 |
| isAnnotationPresent() | 檢查註解 |
| getAnnotations() | 獲取註解 |
// 無參構造
Human h1 = (Human) c1.newInstance();
// 帶參構造
Constructor> cons = c1.getConstructor(String.class, int.class);
Human h2 = (Human) cons.newInstance("Alice", 25);
<clinit> (靜態塊、靜態字段賦值)觸發初始化:new、訪問靜態字段/方法、反射調用、子類初始化、main 類、動態語言調用。
public void save(Object entity) {
Class> clazz = entity.getClass();
Table table = clazz.getAnnotation(Table.class);
String tableName = table.value();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
Column col = field.getAnnotation(Column.class);
String colName = col != null ? col.value() : field.getName();
Object value = field.get(entity);
// 構建 SQL...
}
}
interface Service { void execute(); }
class ServiceImpl implements Service {
public void execute() { System.out.println("執行業務"); }
}
Service proxy = (Service) Proxy.newProxyInstance(
Service.class.getClassLoader(),
new Class[]{Service.class},
(proxy, method, args) -> {
System.out.println("前置增強");
method.invoke(new ServiceImpl(), args);
System.out.println("後置增強");
return null;
}
);
// META-INF/services/com.example.SpiInterface
// 內容: com.example.impl.SpiImplA
ServiceLoader loader = ServiceLoader.load(SpiInterface.class);
for (SpiInterface impl : loader) {
impl.doSomething();
}
Class.forName 除外setAccessible(true) 可訪問私有成員RTTI 是 Java 動態性的核心,Class 對象是類型信息的運行時載體。掌握三種獲取方式、核心反射 API、類加載流程,能構建靈活的框架、實現動態代理、支援插件化架構。但反射破壞封裝、影響性能、繞過編譯期檢查,生產代碼中應謹慎使用,優先考慮多態、接口、註解處理器等靜態方案。