public class Apple extends Fruit {
private String name = "apple";
public Apple() {
tellName();
printName();
}
public void tellName() {
System.out.println("Apple tell name: " + name);
}
public void printName() {
System.out.println("Apple print name: " + name);
}
public static void main(String[] args) {
new Apple();
}
}
class Fruit {
private String name = "fruit";
public Fruit() {
tellName();
printName();
}
public void tellName() {
System.out.println("fruit tell name: " + name);
}
public void printName() {
System.out.println("fruit print name: " + name);
}
}
Apple tell name: null
fruit tell name: fruit
Apple print name: null
fruit print name: fruit
main,執行 new Apple()。Apple() 構造器:
super()(即 Fruit())。Fruit() 構造器:
tellName() → 多態調用子類重寫方法 → Apple.tellName()。Apple.name 尚未初始化(默認 null),輸出 Apple tell name: null。printName() → 多態調用 Apple.printName(),輸出 Apple print name: null。Apple() 構造器:
Apple.name = "apple"(實例變量初始化)。tellName() → Apple.tellName(),輸出 Apple tell name: apple。printName() → Apple.printName(),輸出 Apple print name: apple。| 階段 | 動作 | Apple.name 值 | 調用方法版本 |
|---|---|---|---|
| 1 | 父類構造器開始 | null (默認值) | 子類版本 (多態) |
| 2 | 父類構造器調用方法 | null | 子類版本 |
| 3 | 子類字段初始化 | "apple" | - |
| 4 | 子類構造器調用方法 | "apple" | 子類版本 |
super(),父類構造器優先執行。name 是字段而非方法,父類方法訪問的是父類字段,子類方法訪問子類字段(隱藏而非覆蓋)。init() 方法,構造器完成後顯式調用。final 或 private 防止被覆蓋。this.name / super.name 明確指向。class Fruit {
private String name = "fruit";
public Fruit() {
init(); // 統一初始化入口
}
protected final void init() { // final 防止被覆蓋
tellName();
printName();
}
// ...
}
class Apple extends Fruit {
private String name = "apple";
public Apple() {
super(); // 顯式調用父構造器
// 此處 name 已初始化為 "apple"
tellName(); // 安全調用
printName();
}
// ...
}
該題考察構造器執行順序、多態提前生效、字段初始化時機三大核心機制交互。理解「父類構造器運行時子類字段尚未初始化,但多態已生效」是破解此類問題的關鍵。