首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java super 關鍵字深度解析:父類成員存取、建構子鏈與多型場景實戰

     編輯:Java 相關知識

前言

super 是 Java 中指向父類物件引用的關鍵字,與 this (當前物件引用) 形成對應。它在繼承體系中扮演關鍵角色:存取被遮蔽的父類成員、呼叫父類建構子、調用父類方法實現擴展而非覆寫。本文系統性解析 super 的三大核心用法、記憶體模型與實戰陷阱。

核心用法三大支柱

1. 存取父類成員變數 (欄位遮蔽場景)

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() 擴展功能");
    }
}

2. 呼叫父類建構子 (建構子鏈)

  • 子類建構子首行必須呼叫 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;
    }
}

3. 呼叫父類方法 (擴展而非覆寫)

@Override
public void save() {
    super.save(); // 先執行父類邏輯 (如驗證、日誌)
    // 子類額外邏輯
    this.backup();
}

記憶體模型與對象佈局

new Child() 記憶體佈局:
┌─────────────────────┐
│ Child 物件          │
├─────────────────────┤
│ name = "子類"       │ ← 子類成員
├─────────────────────┤
│ Father 部分         │ ← 父類成員 (內含於子類物件中)
│   name = "父類"     │
│   ...               │
└─────────────────────┘

this  → 指向 Child 物件起始位址
super → 邏輯上指向 Father 部分 (同一塊記憶體,不同視角)

經典面試題:靜態方法與 super

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 僅適用於實例成員 (欄位、方法、建構子),不適用於靜態成員。

多型場景下的 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() 仍按實際物件的繼承鏈向上尋找,體現動態綁定特性。

鑽石繼承與 super 模糊性 (介面預設方法)

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。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved