題目代碼
public class StaticTest {
static int x = 1;
int y;
StaticTest() { y++; }
public static void main(String args[]) {
StaticTest st = new StaticTest();
System.out.println("x=" + x);
System.out.println("st.y=" + st.y);
st = new StaticTest();
System.out.println("st.y=" + st.y);
}
static { x++; }
}
執行結果
x=2
st.y=1
st.y=1
逐行執行順序圖解
| 步驟 | 動作 | x 值 | y 值 | 說明 |
| 1 | 類載入:靜態變數初始化 | 1 | - | static int x = 1 執行 |
| 2 | 類載入:靜態區塊執行 | 2 | - | static { x++; } 執行,x 變 2 |
| 3 | main 開始,建立第一個實例 | 2 | 1 | new StaticTest() → 建構子 y++,y 從 0 變 1 |
| 4 | 輸出第一次 | 2 | 1 | 靜態 x 共享,實例 y 獨有 |
| 5 | 建立第二個實例 | 2 | 1 | 新物件,y 重新從 0 開始,建構子執行後為 1 |
| 6 | 輸出第二次 | 2 | 1 | x 仍為 2(類層級),新物件 y=1 |
核心概念釐清
static 變數(類變數)
- 屬於類,不屬於實例
- 類載入時初始化一次,靜態區塊按出現順序執行
- 所有實例共享同一份記憶體
實例變數
- 屬於具體物件
- 每
new 一次分配新記憶體,預設值 0/false/null
- 建構子中初始化
static 區塊 vs 靜態變數初始化
- 按代碼從上到下順序執行
- 先
static int x = 1,後 static { x++; }
常見誤區
| 誤區 | 正確觀念 |
| static 區塊在 main 前執行? | 在類首次被主動使用時執行(new、存取 static 成員、反射等),不一定在 main 前 |
| 第二次 new 會重跑 static 區塊? | 不會,類只載入一次 |
| st.y 會累積? | 不會,第二次 new 是新物件,y 獨立歸零再 ++ |
記憶體模型示意
方法區(類資料):
StaticTest.class
x = 2 (static)
靜態區塊已執行標記
堆區(實例資料):
st1 (第一個物件) : y = 1
st2 (第二個物件) : y = 1 ← 覆蓋 st 參考,st1 等待 GC
延伸:static 區塊實際用途
- 複雜靜態資料初始化(如載入配置檔、初始化連線池、註冊 JDBC 驅動)
- 單例模式靜態內部類寫法
總結
本題考察三大核心:static 初始化順序(變數 → 區塊)、類變數 vs 實例變數生命週期、建構子每次 new 皆執行。掌握「類載入一次、實例各自獨立」原則,static 相關題型迎刃而解。