「子類物件包含父類部分」,初始化時必須先完成父類初始化。JVM 強制每個子類建構子的第一行執行父類建構子。
class Employee {
public Employee() { System.out.println("Employee()"); }
}
class Trainer extends Employee {
public Trainer() {
// 編譯器自動插入 super();
System.out.println("Trainer()");
}
}
// new Trainer() 輸出:
// Employee()
// Trainer()
⚠️ 前提:父類必須有無參建構子 (或未宣告任何建構子)。若父類只有帶參建構子,子類不寫 super(...) 會編譯錯誤。
class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name; this.salary = salary;
System.out.println("Employee(String, double)");
}
// 故意不提供無參建構子
}
class Trainer extends Employee {
private String course;
public Trainer(String name, double salary, String course) {
super(name, salary); // 必須第一行,傳遞父類所需參數
this.course = course;
System.out.println("Trainer(String, double, String)");
}
}
// new Trainer("Alice", 50000, "Java") 輸出:
// Employee(String, double)
// Trainer(String, double, String)
class Trainer extends Employee {
private String course;
private int level;
// 主建構子
public Trainer(String name, double salary, String course, int level) {
super(name, salary);
this.course = course;
this.level = level;
}
// 便利建構子:預設 level=1
public Trainer(String name, double salary, String course) {
this(name, salary, course, 1); // 呼叫同類別主建構子
}
// 便利建構子:預設 course="General"
public Trainer(String name, double salary) {
this(name, salary, "General"); // 連鎖呼叫
}
}
規則:this(...) 與 super(...) 二擇一,且必須是第一行。不能同時出現。
| 錯誤訊息 | 原因 | 修正 |
|---|---|---|
| Implicit super constructor is undefined | 父類無無參建構子,子類未寫 super(...) | 子類建構子第一行加 super(對應參數) |
| Constructor call must be the first statement | super()/this() 不在第一行 | 移至建構子第一行 |
| Recursive constructor invocation | this() 形成循環呼叫 | 檢查建構子鏈邏輯,確保有終點 |
Trainer 完整記憶體 (含繼承自 Employee 的欄位)。Trainer 建構子第一行 super(name, salary)。Employee 建構子:初始化 name, salary。Trainer 建構子:初始化 course, level。super(...),即使父類有無參建構子,明確傳參更清楚意圖。final,僅提供單一主建構子,便利建構子用 this() 連鎖。overrideMe()),因子類尚未初始化,會導致 NullPointerException 或邏輯錯誤。super(...) 或 this(...)。super() → 要求父類有無參建構子。super(參數)。this() 串聯便利建構子,減少重複程式碼。