super 是 Java 中指向父類物件引用的關鍵字,與 this (當前物件引用) 形成對應。它在繼承體系中扮演關鍵角色:存取被遮蔽的父類成員、呼叫父類建構子、調用父類方法實現擴展而非覆寫。本文系統性解析 super 的三大核心用法、記憶體模型與實戰陷阱。
class Father {
String name = "父類";
void show() { System.out.println("Father.show()"); }
}
class Child extends Father {
String name = "子類"; // 遮蔽父類 name
void test() {
System.out.println(name); // 子類 name
System.out.println(this.name); // 子類 name
System.out.println(super.name); // 父類 name ← 關鍵!
}
@Override
void show() {
super.show(); // 呼叫父類實作
System.out.println("Child.show() 擴展功能");
}
}
super(...) 或 this(...)super() (呼叫父類無參建構子)super(...)class Animal {
String species;
Animal(String species) { this.species = species; }
}
class Cat extends Animal {
String name;
Cat(String name, String species) {
super(species); // 必須首行呼叫父類建構子
this.name = name;
}
}
@Override
public void save() {
super.save(); // 先執行父類邏輯 (如驗證、日誌)
// 子類額外邏輯
this.backup();
}
new Child() 記憶體佈局: ┌─────────────────────┐ │ Child 物件 │ ├─────────────────────┤ │ name = "子類" │ ← 子類成員 ├─────────────────────┤ │ Father 部分 │ ← 父類成員 (內含於子類物件中) │ name = "父類" │ │ ... │ └─────────────────────┘ this → 指向 Child 物件起始位址 super → 邏輯上指向 Father 部分 (同一塊記憶體,不同視角)
class Parent {
static void staticMethod() { System.out.println("Parent static"); }
void instanceMethod() { System.out.println("Parent instance"); }
}
class Child extends Parent {
static void staticMethod() { System.out.println("Child static"); }
@Override void instanceMethod() { System.out.println("Child instance"); }
void test() {
super.instanceMethod(); // ✅ 合法:呼叫父類實例方法
// super.staticMethod(); // ❌ 編譯錯誤:靜態方法屬於類,不屬於物件,無 super 語意
Parent.staticMethod(); // ✅ 正確:用類名呼叫靜態方法
}
}
結論:super 僅適用於實例成員 (欄位、方法、建構子),不適用於靜態成員。
class A { void m() { System.out.println("A"); } }
class B extends A { void m() { System.out.println("B"); super.m(); } }
class C extends B { void m() { System.out.println("C"); super.m(); } }
public class Test {
public static void main(String[] args) {
A obj = new C();
obj.m(); // 輸出:C → B → A
}
}
即使參考型別是父類 A,super.m() 仍按實際物件的繼承鏈向上尋找,體現動態綁定特性。
interface A { default void foo() { System.out.println("A"); } }
interface B extends A { default void foo() { System.out.println("B"); } }
interface C extends A { default void foo() { System.out.println("C"); } }
class D implements B, C {
// 必須覆寫解決衝突
@Override
public void foo() {
B.super.foo(); // 明確指定呼叫 B 的預設方法
C.super.foo(); // 明確指定呼叫 C 的預設方法
}
}
Java 8+ 介面預設方法引入 介面名.super.方法() 語法解決鑽石繼承衝突。
| 錯誤寫法 | 問題 | 正確寫法 |
|---|---|---|
建構子中間呼叫 super() | 必須在首行 | 移至建構子第一行 |
父類無無參建構子,子類不呼叫 super(...) | 編譯錯誤 | 顯式呼叫帶參 super(arg) |
super.staticField | 靜態欄位不屬於物件 | Parent.staticField |
匿名內部類中用 super 存取外部類成員 | super 指向 Object | 用 OuterClass.this.field |
雖然 super 功能強大,但過度繼承導致:
建議:優先考慮組合 + 介面 + 委派,僅在真正的 is-a 關係且需擴展父類行為時使用繼承與 super。