class Window {
Window(int marker) { System.out.println("Window(" + marker + ")"); }
}
class House {
Window w1 = new Window(1); // 成員變量初始化
House() { // 構造器
System.out.println("House()");
w3 = new Window(33); // 構造器內賦值
}
Window w2 = new Window(2); // 成員變量初始化
void f() { System.out.println("f()"); }
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, w2, w3 的 new Window(...) 屬於實例變量初始化,所以在 House() 構造器體之前全部完成,無論它們在代碼中出現在構造器前還是後。
父類靜態變量/塊 → 子類靜態變量/塊
→ 父類實例變量/塊 → 父類構造器
→ 子類實例變量/塊 → 子類構造器
記憶口訣:靜態先行,父前子後,塊前構後。
w1 到構造器後
class House {
House() {
System.out.println("House()");
w3 = new Window(33);
}
Window w1 = new Window(1); // 移到構造器後面
Window w2 = new Window(2);
Window w3 = new Window(3);
}
輸出完全相同:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
證明:實例變量初始化與代碼位置無關,只看聲明順序,且在構造器之前。
class Door { Door() { System.out.println("Door()"); } }
class House {
House() { System.out.println("House()"); w3 = new Window(33); }
Window w1 = new Window(1);
Window w2 = new Window(2);
Window w3 = new Window(3);
Door door = new Door(); // 新增成員
}
輸出:
Window(1)
Window(2)
Window(3)
Door()
House()
Window(33)
f()
Door() 在 House() 之前,再次確認:所有成員變量 (含不同類型) 初始化先於構造器體。
| 誤區 | 真相 |
|---|---|
| 構造器先執行 | 構造器最後執行 |
| 代碼寫在構造器前的先初始化 | 按聲明順序,與構造器位置無關 |
w3 = new Window(33) 是初始化 | 是賦值,發生在構造器體內,晚於初始化 |
| 靜態塊每次 new 都執行 | 類加載時僅執行一次 |
private Window w = new Window(1); 清晰可見。init() 方法,或用構建器模式。
// House 構造器字節碼片段
0: aload_0
1: invokespecial #1 // Object.
4: aload_0
5: new #2 // Window
8: dup
9: iconst_1
10: invokespecial #3 // Window.(int)
13: putfield #4 // w1
16: aload_0
17: new #2
20: dup
21: iconst_2
22: invokespecial #3
25: putfield #5 // w2
28: aload_0
29: new #2
32: dup
33: iconst_3
34: invokespecial #3
37: putfield #6 // w3
40: aload_0
41: new #7 // Door
44: dup
45: invokespecial #8
48: putfield #9 // door
// 以上為實例初始化 (putfield)
// 以下為構造器體
51: getstatic #10 // System.out
54: ldc #11 // "House()"
56: invokevirtual #12
59: aload_0
60: new #2
63: dup
64: bipush 33
66: invokespecial #3
69: putfield #6 // w3 = new Window(33)
72: return
字節碼直觀展示:invokespecial Object. → 所有 putfield (成員初始化) → 構造器體指令。