代碼
class A {
private static A obj = new A(); // 1. 首先執行,調用構造器
public static int num1 = 0; // 2. 然後執行,num1 重置為 0
public static int num2; // 3. 默認 0,構造器中 num2++ 變為 1
private A() { num1++; num2++; }
public static A getInstance() { return obj; }
}
執行順序圖解
- 類加載 → 靜態字段按聲明順序初始化。
- 第 1 行
private static A obj = new A(); 觸發構造器:num1=1, num2=1。
- 第 2 行
public static int num1 = 0; 顯式賦值覆蓋:num1=0。
- 第 3 行
num2 無顯式賦值,保持構造器修改後的 1。
修正:調整聲明順序或使用靜態代碼塊
// 方案一:先聲明基本類型靜態字段
public static int num1 = 0;
public static int num2 = 0;
private static A obj = new A(); // 最後初始化單例
// 方案二:靜態代碼塊統一初始化
static {
num1 = 0; num2 = 0;
obj = new A();
}
核心原則
靜態字段初始化順序 = 聲明順序。單例實例化不應早於基本字段賦值,否則構造器中的修改會被後續顯式賦值覆蓋。