| 特性 | 靜態代碼塊 (static { }) | 靜態方法 (static void method()) |
|---|---|---|
| 觸發時機 | 類加載階段,自動執行,僅執行一次 | 被顯式調用時執行,可多次調用 |
| 典型用途 | 類級別初始化:載入驅動、初始化連接池、解析配置檔 | 工具方法、工廠方法、單例獲取入口 |
| 訪問權限 | 僅能訪問靜態成員(變量/方法) | 僅能直接訪問靜態成員 |
| this/super | 不可使用 | 不可使用 |
new Instance() 才能訪問。this 無指向對象。void foo() { static int x = 0; } 編譯報錯,靜態變量屬於類級別,不能定義在方法作用域內。經典面試題:父類靜態塊 → 子類靜態塊 → 父類非靜態塊 → 父類構造器 → 子類非靜態塊 → 子類構造器。
public class StaticBlockExecutionOrder {
public static int a = 0;
// 1. 父類靜態代碼塊
static {
a = 10;
System.out.println("【父類靜態塊】a = " + a); // 輸出 10
}
// 2. 父類非靜態代碼塊(實例初始化塊)
{
a = 8;
System.out.println("【父類非靜態塊】a = " + a); // 輸出 8
}
// 3. 父類無參構造器
public StaticBlockExecutionOrder() {
this("調用帶參構造器"); // 顯式調用另一構造器
System.out.println("【父類無參構造器】a = " + a); // 輸出 8
}
// 4. 父類帶參構造器
public StaticBlockExecutionOrder(String msg) {
System.out.println(msg + " a = " + a); // 此時 a 仍為 10(靜態塊賦值),非靜態塊尚未執行
System.out.println("【父類帶參構造器】a = " + a);
}
public static void main(String[] args) {
System.out.println("===== main 方法開始 =====");
new StaticBlockExecutionOrder();
System.out.println("===== main 方法結束 =====");
}
}
【父類靜態塊】a = 10
===== main 方法開始 =====
【父類非靜態塊】a = 8
調用帶參構造器 a = 10 <-- 關鍵點!
【父類帶參構造器】a = 10
【父類無參構造器】a = 8
===== main 方法結束 =====
new StaticBlockExecutionOrder(),先隱式調用無參構造器。this("...") 顯式調用帶參構造器(構造器鏈)。a 仍保持靜態塊賦值的 10。a 改為 8。a = 8。核心結論:構造器鏈調用(this(...)或super(...))必須是構造器第一條語句,且會中斷當前構造器流程,優先執行目標構造器。非靜態塊在所有構造器鏈調用完成後、當前構造器體執行前統一執行。
public class StaticBlockDemo {
static { System.out.println("靜態塊"); }
{ System.out.println("非靜態塊(實例初始化塊)"); }
public StaticBlockDemo() { System.out.println("構造方法"); }
public static void main(String[] args) {
new StaticBlockDemo();
System.out.println("--- 分割線 ---");
new StaticBlockDemo();
}
}
靜態塊
非靜態塊(實例初始化塊)
構造方法
--- 分割線 ---
非靜態塊(實例初始化塊)
構造方法
ExceptionInInitializerError,類不可用,務必 try-catch 兜底。