class Father {
void methodA() { System.out.println("Father.A"); }
Son sonRef = new Son(); // 父類持有子類實例引用
void callSonA() { sonRef.methodA(); }
}
class Son extends Father {
@Override void methodA() { System.out.println("Son.A"); }
}
問題:在 `Father` 中調用 `sonRef.methodA()` 時,執行的是 `Father.A` 還是 `Son.A`?
「假如你實例化 son,jvm 會根據繼承關系先調用父類構造函數,但是在調用所有構造函數之前會將每個類的對象初始化成二進制的 0,所以父類任然會調用子類的方法,但是結果完全不可預料,所以強烈建議不要這樣寫。」
class Father {
Father() {
init(); // 構造器中調用可覆蓋方法
}
void init() { System.out.println("Father.init"); }
}
class Son extends Father {
String name = "Son"; // 實例變量初始化
Son() {
super(); // 隱式調用 Father()
System.out.println("Son constructor, name=" + name);
}
@Override void init() {
System.out.println("Son.init, name.length=" + name.length()); // 此時 name 尚未初始化!
}
}
new Son();
// 輸出:
// Son.init, name.length=0 <-- name 為 null,拋出 NPE 或輸出 0
// Son constructor, name=Son
| 場景 | 調用結果 | 風險等級 |
|---|---|---|
| 構造器外調用 `sonRef.methodA()` | 執行 `Son.A`(正常多態) | 安全 |
| 父類構造器中調用 `this.methodA()` | 執行 `Son.A`,但子類字段未初始化 | 極高危 |
| 父類構造器中調用 `sonRef.methodA()` | 同上,子類字段未初始化 | 極高危 |
鐵律:構造器、最終化器、clone、反序列化等「對象不完全構建」階段,**絕不調用可覆蓋方法**。