首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

深度解析 Java 類加載順序:靜態初始化、構造器、繼承鏈全流程

     編輯:Java 相關知識

核心結論先行

Java 類加載與實例化遵循嚴格順序,掌握此機制對理解繼承、序列化、熱部署等進階主題至關重要。本文通過代碼實例與輸出分析,系統梳理完整生命周期。

理論基礎:四階段加載順序

  1. 類加載階段:JVM 首次使用類時,按順序執行 靜態變量賦值 → 靜態初始化塊,僅執行一次
  2. 實例化階段:調用 new 時,沿繼承鏈 父類先於子類,依次執行:
    • 父類非靜態初始化塊(實例初始化塊)
    • 父類構造器
    • 子類非靜態初始化塊
    • 子類構造器
  3. 銷毀階段:GC 回收時 子類先於父類 執行 finalize()
  4. 靜態方法調用:首次調用靜態方法觸發類加載,靜態成員按聲明順序初始化

代碼實驗:父子類完整生命周期

父類 Parent

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("銷毀父類");
    }
}

子類 Child

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("銷毀子類");
    }
}

測試類 Test

public class Test {
    public static void main(String[] args) {
        Parent.parentStaticMethod();  // 僅調用父類靜態方法
        // Child child = new Child();  // 註釋掉實例化
    }
}

輸出分析與關鍵規律

場景 1:僅調用靜態方法

父類靜態方法2
父類靜態初始化塊
父類靜態方法

規律:靜態變量 t 賦值觸發 parentStaticMethod2() → 類加載執行靜態初始化塊 → 調用目標靜態方法。子類完全未加載。

場景 2:實例化子類(取消註釋 new Child())

父類靜態方法2
父類靜態初始化塊
子類靜態初始化塊
父類非靜態初始化塊
父類構造器
子類非靜態初始化塊
子類構造器

關鍵順序驗證:

  • 靜態階段:父類靜態 → 子類靜態(繼承鏈自上而下)
  • 實例階段:父類塊 → 父構造器 → 子類塊 → 子構造器
  • 靜態方法 parentStaticMethod() 調用時類已加載,不再重複初始化

進階陷阱:靜態變量聲明順序影響

若將 static int t = parentStaticMethod2(); 移至靜態初始化塊 之後,輸出變為:

父類靜態方法2
父類靜態初始化塊
父類靜態方法2

原因:靜態成員按 源碼順序 初始化,靜態塊執行時 t 尚未賦值,再次觸發方法調用。

總結

Java 類加載順序鐵律:靜態優於實例、父類優於子類、聲明順序決定初始化序列。實戰中避免在靜態初始化中依賴未初始化的靜態成員,構造器中勿調用可覆寫方法。理解此機制,可有效排查繼承鏈初始化異常、單例模式線程安全等疑難問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved