Java 類加載與初始化順序是面試高頻考點,也是理解對象創建生命週期的基礎。本文通過實測代碼驗證,系統總結完整執行時序。
靜態字段/靜態代碼塊 (按代碼順序) → 靜態方法 → 構造器 (含非靜態字段/非靜態代碼塊) → 普通方法
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();
}
}
getA()
靜態代碼塊 a=10
getC()
非靜態代碼塊 c=30
構造器
普通方法
a = getA() 觸發 getA() 執行,早於靜態代碼塊b=20 在代碼塊後聲明,初始化順序按代碼先後c=getC()、非靜態代碼塊均在構造器體前執行Class 對象<clinit>() 方法
<clinit> 先於子類 (遞歸)<clinit> (除非使用父接口靜態字段)<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記住口訣:「靜態先行按順序,父類靜態再子類;實例父先子後行,字段塊前構造器」。掌握此順序,可精準預測對象創建時的狀態變化,編寫無副作用的初始化邏輯。