Java 類加載與實例化遵循嚴格順序,掌握此機制對理解繼承、序列化、熱部署等進階主題至關重要。本文通過代碼實例與輸出分析,系統梳理完整生命周期。
new 時,沿繼承鏈 父類先於子類,依次執行:
finalize()public class Parent {
public static int t = parentStaticMethod2(); // 靜態變量賦值調用靜態方法
{ System.out.println("父類非靜態初始化塊"); } // 實例初始化塊
static { System.out.println("父類靜態初始化塊"); } // 靜態初始化塊
public Parent() { System.out.println("父類構造器"); }
public static int parentStaticMethod() {
System.out.println("父類靜態方法"); return 10;
}
public static int parentStaticMethod2() {
System.out.println("父類靜態方法2"); return 9;
}
@Override protected void finalize() throws Throwable {
super.finalize();
System.out.println("銷毀父類");
}
}
public class Child extends Parent {
{ System.out.println("子類非靜態初始化塊"); }
static { System.out.println("子類靜態初始化塊"); }
public Child() { System.out.println("子類構造器"); }
public static int childStaticMethod() {
System.out.println("子類靜態方法"); return 1000;
}
@Override protected void finalize() throws Throwable {
super.finalize();
System.out.println("銷毀子類");
}
}
public class Test {
public static void main(String[] args) {
Parent.parentStaticMethod(); // 僅調用父類靜態方法
// Child child = new Child(); // 註釋掉實例化
}
}
父類靜態方法2 父類靜態初始化塊 父類靜態方法
規律:靜態變量 t 賦值觸發 parentStaticMethod2() → 類加載執行靜態初始化塊 → 調用目標靜態方法。子類完全未加載。
父類靜態方法2 父類靜態初始化塊 子類靜態初始化塊 父類非靜態初始化塊 父類構造器 子類非靜態初始化塊 子類構造器
關鍵順序驗證:
parentStaticMethod() 調用時類已加載,不再重複初始化若將 static int t = parentStaticMethod2(); 移至靜態初始化塊 之後,輸出變為:
父類靜態方法2 父類靜態初始化塊 父類靜態方法2
原因:靜態成員按 源碼順序 初始化,靜態塊執行時 t 尚未賦值,再次觸發方法調用。
Java 類加載順序鐵律:靜態優於實例、父類優於子類、聲明順序決定初始化序列。實戰中避免在靜態初始化中依賴未初始化的靜態成員,構造器中勿調用可覆寫方法。理解此機制,可有效排查繼承鏈初始化異常、單例模式線程安全等疑難問題。