| 操作 | 是否觸發初始化 | 說明 |
ClassName.class | 否 | 僅取得 Class 參考 |
Class.forName("Name") | 是 | 立即載入、鏈接、初始化 (執行 static 區塊) |
| 訪問 static final 編譯期常量 | 否 | 常量已內聯到調用類 |
| 訪問 static 非常量欄位 | 是 | 觸發初始化 |
| new ClassName() | 是 | 建構子隱含 static |
演示程式碼
class Data1 { static final int a = 1; static { System.out.println("init Data1"); } }
class Data2 { static final double b = Math.random(); static { System.out.println("init Data2"); } }
class Data3 { static int c = 3; static { System.out.println("init Data3"); } }
public class Demo {
public static void main(String[] args) throws Exception {
Class c1 = Data1.class; // 不初始化
System.out.println(Data1.a); // 不初始化 (編譯期常量)
System.out.println(Data2.b); // 初始化 Data2
Class.forName("Data3"); // 初始化 Data3
}
}
// 輸出:
// init Data2
// 0.123456...
// init Data3
// 3
泛型 Class 與類型安全
Class<Integer> intClass = Integer.class; // 限制只能指向 Integer
// intClass = Double.class; // 編譯錯誤
Class<?> wildcard = Integer.class; // 通配符,可指向任意
wildcard = String.class; // OK
Class<? extends Number> numClass = Integer.class; // 上界
numClass = Double.class; // OK
// numClass = String.class; // 編譯錯誤
泛型下的 newInstance()
Class<? extends Number> num = Integer.class;
Number n = num.newInstance(); // 回傳 Number,非 Integer (擦除後)
Object o = num.getSuperclass().newInstance(); // 僅得 Object
新式轉型語法:cast()
Animal a = new Dog();
Class<Dog> dogClass = Dog.class;
Dog d = dogClass.cast(a); // 等同 (Dog)a,但可用於泛型場景
適用於:編譯期類型未知,但持有 Class<T> 參考時進行安全轉型。
instanceof 與 Class.isInstance
instanceof
if (shape instanceof Circle) ((Circle)shape).roll();
- 檢查對象是否為指定類/介面/子類實例。
null instanceof X 永遠為 false。
Class.isInstance (靜態化 instanceof)
Circle.class.isInstance(shape); // 等同 shape instanceof Circle
// 優勢:Class 物件可作為參數傳遞、儲存、泛型化
統計形狀個數:從 instanceof 到 isInstance
// 傳統:硬編碼每種類型
if (s instanceof Circle) counter.count("Circle");
if (s instanceof Square) counter.count("Square");
// 進階:類型列表驅動
List<Class<? extends Shape>> types = Arrays.asList(Circle.class, Square.class, Triangle.class);
for (Shape s : shapes) {
for (Class<? extends Shape> cls : types) {
if (cls.isInstance(s)) counter.count(cls.getSimpleName());
}
}
等價性對比
Circle c = new Circle();
c instanceof Circle; // true
Circle.class.isInstance(c); // true
c.getClass() == Circle.class; // true (精確類型)
c.getClass().equals(Circle.class); // true
c.getClass() == Shape.class; // false (不考慮繼承)
Shape.class.isInstance(c); // true (考慮繼承)
RTTI 與反射的分水嶺
| 特性 | 傳統 RTTI | 反射 |
| 類型在編譯期是否已知 | 是 | 否 (字串名稱) |
| 核心 API | Class, instanceof, cast | Class, Method, Field, Constructor |
| 可存取 private 成員 | 否 | 是 (setAccessible) |
| 效能 | 高 (JIT 優化) | 較低 (需安全檢查、參數檢查) |
| 典型場景 | 多態分派、類型檢查、框架掃描註解 | 動態代理、序列化、依賴注入容器 |
總結
RTTI 是 Java 類型系統的運行期基石。掌握 Class 物件取得方式、初始化時機、泛型 Class、instanceof/isInstance/cast 三劍客,能寫出類型安全、效能優越的框架級代碼。記住:優先用類字面常量、善用泛型 Class 限制、反射留給真正需要動態性的場景。
- 上一篇文章: Struts2 攔截 404 錯誤最佳實踐:web.xml + struts.xml 雙重防護
- 下一篇文章: JVM、JRE、JDK 三者關係與差異完整圖解:從原始碼到機器指令
Copyright ©
程式碼之家 All Rights Reserved