核心結論:初始化順序鐵律
- 父類靜態欄位/靜態區塊(按聲明順序)
- 子類靜態欄位/靜態區塊(按聲明順序)
- 父類實例欄位/實例初始化區塊(按聲明順序)
- 父類建構器
- 子類實例欄位/實例初始化區塊(按聲明順序)
- 子類建構器
驗證範例與輸出分析
public class Window {
Window(int marker) { System.out.println("Window(" + marker + ")"); }
}
public class House {
Window w1 = new Window(1); // 實例欄位初始化
House() {
System.out.println("House()");
w3 = new Window(33); // 建構器內賦值
}
Window w2 = new Window(2);
Window w3 = new Window(3);
}
public class OrderOfInitialization {
public static void main(String[] args) {
House h = new House();
h.f();
}
}
/* 輸出:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*/
關鍵觀察
- 無論欄位聲明在建構器前後,實例欄位初始化總在建構器體之前完成
- 將
w1 移至建構器後,輸出順序不變,證明聲明位置不影響初始化時機
- 新增
Door 類欄位,其初始化同樣插在建構器體之前
最佳實踐建議
- 避免在建構器中調用可被覆寫的方法(子類欄位尚未初始化)
- 將複雜初始化邏輯集中在建構器,欄位聲明保持簡單
- 靜態初始化異常會導致
ExceptionInInitializerError,需謹慎處理
- 使用
final 欄位強制在宣告或建構器末尾完成初始化