統一執行順序口訣
- 依賴類成員(靜態欄位/靜態塊)
- 父類靜態成員 → 子類靜態成員
- 父類普通成員(實例欄位/實例塊) → 父類建構器
- 子類普通成員 → 子類建構器
實戰驗證程式碼
public class InitOrderDemo {
private static InitOrderDemo demo = new InitOrderDemo(); // ① 依賴類靜態欄位
private SubClass sub = new SubClass(); // ② 依賴類實例欄位
static { System.out.println("靜態塊"); } // ③ 本類靜態塊
public InitOrderDemo() { System.out.println("建構器"); } // ④ 本類建構器
public static void main(String[] args) { System.out.println("main"); }
static class SuperClass {
{ System.out.println("父類實例塊"); }
SuperClass() { System.out.println("父類建構器"); }
static { System.out.println("父類靜態塊"); }
}
static class SubClass extends SuperClass {
static { System.out.println("子類靜態塊"); }
{ System.out.println("子類實例塊"); }
SubClass() { System.out.println("子類建構器"); }
}
}
輸出結果與解析
父類靜態塊 ← 依賴類 SubClass 載入觸發父類靜態初始化
子類靜態塊 ← SubClass 自身靜態初始化
父類實例塊 ← new SubClass() 隱式 super() 先跑父類實例初始化
父類建構器
子類實例塊
子類建構器
建構器 ← InitOrderDemo 自身建構器
靜態塊 ← InitOrderDemo 靜態塊(注意:靜態欄位 demo 初始化時已跑完以上,此處為類載入後續靜態塊)
main
關鍵細節
- 靜態欄位/塊:類載入時按聲明順序執行,僅一次
- 實例塊:每次
new 物件前於建構器執行,編譯器將其複製進每個建構器開頭(super() 之後)
- 反編譯視角:實例欄位初始化與實例塊會被搬移至建構器中,順序保持
- 循環依賴風險:靜態欄位 `new ThisClass()` 會觸發遞迴初始化,需極度謹慎
面試必考點總結表
| 場景 | 順序 |
| 單一類別 | 靜態欄位/塊 → 實例欄位/塊 → 建構器 |
| 繼承鏈 | 父靜態 → 子靜態 → 父實例/建構 → 子實例/建構 |
| 依賴類 | 被依賴類完全初始化後,依賴類才繼續 |