理解 RTTI 運作,先搞懂型別資訊在執行期如何表示。用特殊Class 物件(或稱元類)包含類別相關資訊。實際上我們用 Class 物件建立該類別所有「常規」物件。
每個類別對應一個 Class 物件。寫新類別時同時建立 Class 物件(儲存於同名 .class 檔)。執行期想生成物件時,JVM 檢查該型別 Class 物件是否已載入;未載入則尋找 .class 檔載入。Java 程式啟動非完全載入,與傳統語言不同。
一旦 Class 物件進入記憶體,即用它建立該型別所有物件。
//: SweetShop.java
class Candy { static { System.out.println("Loading Candy"); } }
class Gum { static { System.out.println("Loading Gum"); } }
class Cookie { static { System.out.println("Loading Cookie"); } }
public class SweetShop {
public static void main(String[] args) {
System.out.println("inside main");
new Candy(); System.out.println("After creating Candy");
try { Class.forName("Gum"); } catch(ClassNotFoundException e) { e.printStackTrace(); }
System.out.println("After Class.forName(\"Gum\")");
new Cookie(); System.out.println("After creating Cookie");
}
} ///:~
每類別有 static 區塊在首次載入時執行。輸出顯示載入時機:
inside main
Loading Candy
After creating Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
每個 Class 僅在需要時載入,static 初始化隨載入執行。另一 JVM 可能預測 main() 需 Candy/Cookie 而預先載入(Gum 因 forName() 動態載入無法預測)。行為不保證一致。
Gum.class 取得 Class 參考。更簡單、更安全(編譯期檢查)、效率更高(無方法呼叫)。適用於一般類別、介面、陣列、基本型別。
| 類別字面常數 | 等價於 |
|---|---|
boolean.class | Boolean.TYPE |
char.class | Character.TYPE |
byte.class | Byte.TYPE |
short.class | Short.TYPE |
int.class | Integer.TYPE |
long.class | Long.TYPE |
float.class | Float.TYPE |
double.class | Double.TYPE |
void.class | Void.TYPE |
各包裝器類別的 TYPE 欄位產生對應基本型別的 Class 參考。