在 Java 類別載入與物件建立過程中,靜態區塊、非靜態區塊(實例初始化區塊)與建構子的執行順序是面試高頻考點,也是理解 JVM 類別載入機制的關鍵。本文通過詳細的代碼實驗與輸出分析,徹底釐清這三者的執行規則與繼承關係下的複雜行為。
| 區塊類型 | 執行時機 | 執行次數 | 典型用途 |
|---|---|---|---|
靜態區塊 static { } | 類別載入時(JVM 首次使用該類) | 僅一次 | 靜態變數初始化、單例模式、註冊驅動程式 |
非靜態區塊 { } | 每次 new 物件前,建構子執行前 | 每次建立物件 | 共用初始化邏輯、匿名內部類別屬性初始化 |
| 建構子 | 非靜態區塊執行後 | 每次建立物件 | 物件具體狀態初始化、參數驗證 |
public class TestStatic {
static { System.out.println("靜態區塊"); }
{ System.out.println("非靜態區塊"); }
public TestStatic() { System.out.println("建構子"); }
public static void main(String[] args) {
new TestStatic();
System.out.println("---分割線---");
new TestStatic();
}
}
輸出結果:
靜態區塊 非靜態區塊 建構子 ---分割線--- 非靜態區塊 建構子
當子類別繼承父類別時,執行順序遵循「父靜態 → 子靜態 → 父非靜態 → 父建構子 → 子非靜態 → 子建構子」的鏈式規則。關鍵點:
new 物件、反射)new 子類別物件都會完整執行一次父子鏈super():子類別建構子首行隱含呼叫父類別無參建構子,觸發父類別初始化鏈// 父類別
class Base {
static { System.out.println("父靜態區塊"); }
{ System.out.println("父非靜態區塊"); }
Base() { System.out.println("父建構子"); }
static void staticMethod() { System.out.println("父靜態方法"); }
}
// 子類別
class Derived extends Base {
static { System.out.println("子靜態區塊"); }
{ System.out.println("子非靜態區塊"); }
Derived() { System.out.println("子建構子"); }
static void staticMethod() { System.out.println("子靜態方法"); }
}
public class Test {
public static void main(String[] args) {
System.out.println("=== 測試1: 僅調用父類別靜態方法 ===");
Base.staticMethod();
System.out.println("\n=== 測試2: 調用子類別靜態方法 ===");
Derived.staticMethod();
System.out.println("\n=== 測試3: new 子類別物件 ===");
new Derived();
System.out.println("\n=== 測試4: 再次 new 子類別物件 ===");
new Derived();
}
}
=== 測試1: 僅調用父類別靜態方法 === 父靜態區塊 父靜態方法 === 測試2: 調用子類別靜態方法 === 父靜態區塊 子靜態區塊 子靜態方法 === 測試3: new 子類別物件 === 父非靜態區塊 父建構子 子非靜態區塊 子建構子 === 測試4: 再次 new 子類別物件 === 父非靜態區塊 父建構子 子非靜態區塊 子建構子
static final int A = 1;)優於靜態區塊,運算期常量(static final int B = compute();)在靜態區塊中按順序執行throws,否則區塊內必須捕獲處理InstanceHolder 類別實現延遲載入@PostConstruct 本質上在非靜態區塊後、建構子後執行
類別載入階段 物件實例化階段(每次 new)
┌─────────────────┐ ┌─────────────────────────────┐
│ 父靜態區塊/欄位 │───▶│ 父非靜態區塊/欄位 │
│ 子靜態區塊/欄位 │ │ 父建構子 │
│ (僅首次觸發) │ │ 子非靜態區塊/欄位 │
└─────────────────┘ │ 子建構子 │
└─────────────────────────────┘
掌握這套機制,不僅能應付面試,更能在設計框架、排查類別載入死鎖、優化啟動效能時遊刃有餘。建議動手跑通文中所有實驗,在腦海中建立完整的時序圖譜。