| 階段 | 執行順序 | 執行次數 | 典型用途 |
|---|---|---|---|
| 靜態初始化塊 | 類加載時,按繼承鏈父→子、聲明順序 | 每類僅一次(ClassLoader 加載時) | 靜態字段複雜初始化、單例預熱、註冊驅動 |
| 實例初始化塊 | 構造函數調用前,按繼承鏈父→子、聲明順序 | 每次 new 實例執行一次 | 多構造器公共邏輯提取、最終字段賦值 |
| 構造函數 | super() 後、實例初始化塊後、本類構造函數體 | 每次 new 實例執行一次 | 實例化核心邏輯、依賴注入 |
class A {
static { System.out.println("Static init A."); }
{ System.out.println("Instance init A."); }
A() { System.out.println("Constructor A."); }
}
class B extends A {
static { System.out.println("Static init B."); }
{ System.out.println("Instance init B."); }
B() { System.out.println("Constructor B."); }
}
class C extends B {
static { System.out.println("Static init C."); }
{ System.out.println("Instance init C."); }
C() { System.out.println("Constructor C."); }
}
public class Main {
static { System.out.println("Static init Main."); }
{ System.out.println("Instance init Main."); }
Main() { System.out.println("Constructor Main."); }
public static void main(String[] args) {
new C(); // 單次實例化
}
}
Static init Main.
Static init A.
Static init B.
Static init C.
Instance init A.
Constructor A.
Instance init B.
Constructor B.
Instance init C.
Constructor C.
Static init Main.
Static init A.
Static init B.
Static init C.
Instance init A.
Constructor A.
Instance init B.
Constructor B.
Instance init C.
Constructor C.
Instance init A.
Constructor A.
Instance init B.
Constructor B.
關鍵觀察:靜態塊僅首次加載執行;實例塊與構造函數每次實例化均按「父類實例塊 → 父類構造器 → 子類實例塊 → 子類構造器」順序執行。
public Main();
Code:
0: aload_0
1: invokespecial #1 // java/lang/Object."":()V
4: getstatic #2 // System.out
7: ldc #3 // "Instance init Main."
9: invokevirtual #4 // println
12: getstatic #2
15: ldc #5 // "Constructor Main."
17: invokevirtual #4
20: return
**發現**:實例初始化塊代碼被編譯器**前置插入**到構造函數體中,位於 `super()` 調用之後、構造函數自有代碼之前。
C();
Code:
0: aload_0
1: invokespecial #1 // B."":()V
4: getstatic #2
7: ldc #3 // "Instance init C."
9: invokevirtual #4
12: getstatic #2
15: ldc #5 // "Constructor C."
17: invokevirtual #4
20: return
證實:子類構造函數首行必調 `super()`,隨後執行本類實例塊,最後執行構造函數體。
初始化塊不是語法糖,而是編譯器協助的**構造器模板方法模式**實現:
善用它們可提升代碼復用與可讀性,濫用則增加認知負擔。**原則:能用構造函數/字段聲明初始化的,就不寫初始化塊。**