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

Java 類初始化順序詳解:靜態/非靜態字段、代碼塊、構造器、方法執行時序

     編輯:Java 相關知識

前言

Java 類加載與初始化順序是面試高頻考點,也是理解對象創建生命週期的基礎。本文通過實測代碼驗證,系統總結完整執行時序。

一、核心結論速查表

靜態字段/靜態代碼塊 (按代碼順序) → 靜態方法 → 構造器 (含非靜態字段/非靜態代碼塊) → 普通方法

二、實驗驗證過程

2.1 測試代碼結構

public class InitOrderTest {
    // 靜態字段
    static int a = getA();
    static int b = 20;
    
    // 非靜態字段
    int c = getC();
    int d = 40;
    
    // 靜態代碼塊
    static { System.out.println("靜態代碼塊 a=" + a); }
    
    // 非靜態代碼塊
    { System.out.println("非靜態代碼塊 c=" + c); }
    
    // 靜態方法
    static int getA() { System.out.println("getA()"); return 10; }
    
    // 非靜態方法
    int getC() { System.out.println("getC()"); return 30; }
    
    // 構造器
    public InitOrderTest() { System.out.println("構造器"); }
    
    // 普通方法
    public void normalMethod() { System.out.println("普通方法"); }
    
    public static void main(String[] args) {
        new InitOrderTest().normalMethod();
    }
}

2.2 運行輸出

getA()
靜態代碼塊 a=10
getC()
非靜態代碼塊 c=30
構造器
普通方法

2.3 關鍵觀察點

  1. 靜態字段初始化調用靜態方法:a = getA() 觸發 getA() 執行,早於靜態代碼塊
  2. 靜態字段與靜態代碼塊平級:b=20 在代碼塊後聲明,初始化順序按代碼先後
  3. 非靜態字段/代碼塊在構造器前:c=getC()、非靜態代碼塊均在構造器體前執行
  4. 構造器最後執行:實例化完成後調用普通方法

三、JVM 規範視角的完整初始化流程

3.1 類加載階段 (Class Loading)

  1. 加載:讀取 .class 字節碼生成 Class 對象
  2. 驗證/準備/解析
  3. 初始化:執行 <clinit>() 方法
    • 按文本順序執行 靜態字段賦值 與 靜態代碼塊
    • 父類 <clinit> 先於子類 (遞歸)
    • 接口不執行父接口 <clinit> (除非使用父接口靜態字段)

3.2 對象實例化階段 (Instantiation)

  1. 分配對象內存 (含父類字段)
  2. 默認值初始化 (0/null/false)
  3. 執行 <init>() (構造器)
    • 隱式/顯式 super() → 父類 <init> 遞歸
    • 按文本順序執行 非靜態字段賦值 與 非靜態代碼塊
    • 執行構造器體代碼

四、繼承場景下的順序驗證

class Parent {
    static { System.out.println("Parent 靜態塊"); }
    { System.out.println("Parent 非靜態塊"); }
    Parent() { System.out.println("Parent 構造器"); }
}

class Child extends Parent {
    static { System.out.println("Child 靜態塊"); }
    { System.out.println("Child 非靜態塊"); }
    Child() { System.out.println("Child 構造器"); }
}

new Child();
輸出:

Parent 靜態塊
Child 靜態塊
Parent 非靜態塊
Parent 構造器
Child 非靜態塊
Child 構造器

五、最佳實踐與避坑

  • 靜態初始化避免循環依賴:類間相互引用靜態字段會導致 ClassCircularityError
  • 構造器不調用可覆寫方法:防止子類字段未初始化被父類構造器間接訪問 (見 ID 114044 陷阱)
  • 非靜態代碼塊提取公共初始化邏輯:多構造器共享初始化代碼
  • 靜態工廠方法替代複雜構造器:將複雜初始化移出構造器,提高可測試性

六、總結

記住口訣:「靜態先行按順序,父類靜態再子類;實例父先子後行,字段塊前構造器」。掌握此順序,可精準預測對象創建時的狀態變化,編寫無副作用的初始化邏輯。

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