反射是 Java 動態性的基石,允許運行時檢查類結構、創建實例、調用方法、訪問字段(含 private)。框架開發、依賴注入、序列化、動態代理均建立於此。
每個類在 JVM 中僅有一個 Class<T> 實例,由類加載器加載 .class 文件時創建。它是反射的入口,包含類的完整元數據:修飾符、父類、接口、字段、方法、構造器、註解等。
// Class 對象類型示例
Class c1 = String.class; // 具體類型
Class> c2 = Class.forName("java.lang.String"); // 未知類型用通配符
Class c3 = int[].class; // 數組類型
Class c4 = void.class; // 基本類型 void
.getClass():Class c = "abc".getClass(); — 需要實例,運行時確定。Class.forName("全限定名"):Class c = Class.forName("com.test.MyObject"); — 僅需字符串名,支援動態加載,**會觸發類初始化**(執行 static 塊)。.class:Class c = MyObject.class; — 編譯期檢查,**不觸發類初始化**,性能最佳,推薦優先使用。Class clazz = User.class;
// 1. 創建實例(需無參構造器)
User user = (User) clazz.getDeclaredConstructor().newInstance();
// 2. 訪問私有字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 破壞封裝
nameField.set(user, "Tom");
// 3. 調用私有方法
Method sayHi = clazz.getDeclaredMethod("sayHi", String.class);
sayHi.setAccessible(true);
sayHi.invoke(user, "Hello");
// 4. 掃描註解
if (clazz.isAnnotationPresent(Table.class)) { ... }
Method/Field/Constructor 對象,或使用 MethodHandle / VarHandle(Java 9+)。setAccessible(true) 可繞過封裝,模塊化系統中需 opens 導出包。--add-opens 才能反射訪問。