三種獲取 Class 物件的途徑
- `Class.forName("全限定類名")`
- `類名.class`
- `實例物件.getClass()`
實驗驗證:只會觸發一次靜態初始化
class TestClassType {
static { System.out.println("---靜態初始化---"); }
{ System.out.println("---非靜態初始化---"); }
TestClassType() { System.out.println("---建構子---"); }
}
public class TestClass {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("TestClassType");
Class c2 = TestClassType.class;
TestClassType obj = new TestClassType();
Class c3 = obj.getClass();
System.out.println(c1 == c2 && c2 == c3); // true
}
}
輸出結果
---靜態初始化---
class TestClassType
class TestClassType
---非靜態初始化---
---建構子---
class TestClassType
true
核心結論
- 同一 JVM 中,同一類僅有一個 Class 物件(單例模式)。
- 靜態初始化發生在類首次被主動使用時(對應 JVM 初始化階段)。
- 非靜態初始化與建構子在 `new` 實例時執行。
- 三種獲取方式本質相同:JVM 先檢查方法區是否已加載,否則載入 `.class` 並生成 Class 物件。
類加載與實例化的分離
// 類加載(含靜態初始化)
Class.forName("TestClassType"); // 僅加載,不實例化
// 實例化(含非靜態初始化 + 建構子)
new TestClassType();
實務啟示
- 反射框架(Spring、Hibernate)大量使用 `Class.forName` 實現延遲加載與解耦。
- 單例模式中 `Enum` 或 `static holder` 利用類加載機制保證線程安全。
- 熱部署/模組化(OSGi、Jigsaw)核心即操作 ClassLoader 隔離 Class 物件命名空間。