子類構造過程中,必須調用父類構造器 — 因為子類對象內存布局包含父類對象部分,必須先初始化父類部分。
class Parent {
public Parent() { System.out.println("Parent()"); }
}
class Child extends Parent {
public Child() {
// 編譯器自動插入 super(); 作為第一行
System.out.println("Child()");
}
}
// 輸出:Parent() → Child()
class Parent {
private String name;
public Parent(String name) { // 唯一構造器,有參
this.name = name;
}
}
class Child extends Parent {
public Child() {
// super(); // ❌ 編譯錯誤:父類無無參構造器
super("子類指定名稱"); // ✅ 必須顯式調用
}
}
class Parent {
private String name;
// 顯式提供無參構造器 (即使邏輯為空)
public Parent() { }
public Parent(String name) {
this.name = name;
}
}
class Child extends Parent {
public Child() {
// 可選:super(); // 隱式調用,編譯器自動插入
}
public Child(String name) {
super(name); // 顯式調用有參構造器
}
}
建議:父類若定義了有參構造器,**始終顯式提供無參構造器**,避免子類編譯報錯,提高擴展性。
new Child("test")
│
▼
Child(String) 構造器
│
├── super("test") 顯式調用
│ │
│ ▼
│ Parent(String) 構造器執行
│ │
│ ├── 父類靜態初始化 (類加載時已完成)
│ ├── 父類實例變量賦值
│ ├── 父類實例初始化塊 {}
│ └── 父類構造器體代碼
│ │
│ ▼
│ 返回 Child 構造器
│
├── 子類實例變量賦值
├── 子類實例初始化塊 {}
└── 子類構造器體代碼
class Animal {
private String name;
private int age;
public Animal() { this("無名", 0); }
public Animal(String name) { this(name, 0); }
public Animal(String name, int age) {
this.name = name; this.age = age;
}
}
class Dog extends Animal {
private String breed;
public Dog() { super(); } // 調用 Animal()
public Dog(String name) { super(name); } // 調用 Animal(String)
public Dog(String name, int age) { super(name, age); }
public Dog(String name, int age, String breed) {
super(name, age);
this.breed = breed;
}
}
子類構造器通過 super(...) 選擇調用父類哪個重載構造器,實現參數透傳。
| 錯誤代碼 | 原因 | 修正 |
|---|---|---|
super(); 不在第一行 | 構造器鏈要求 super() 必須是第一條語句 | 移至首行 |
同時調用 this() 和 super() | 二者互斥,只能二選一 | 鏈式調用:this() → 另一構造器 → super() |
| 父類無無參構造器,子類不寫 super | 編譯器嘗試插入 super() 失敗 | 顯式 super(參數) 或父類加無參構造器 |
| 靜態方法調用 super() | 靜態方法無 this,無構造器鏈 | 不可在靜態方法中使用 super() |
所有類隱式繼承 Object,Object() 是構造器鏈的最終環節。即使類聲明 extends Object,機制不變。
super() 或顯式 super(args))super() 與 this() 二選一,且必須在首行