Java super 關鍵字

super 關鍵字用於存取父類別的成員,包括建構子、方法和變數。

呼叫父類別建構子

使用 super() 呼叫父類別的建構子:

class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
        System.out.println("Animal 建構子");
    }
}

class Dog extends Animal {
    private String breed;

    public Dog(String name, String breed) {
        super(name);  // 呼叫父類別建構子
        this.breed = breed;
        System.out.println("Dog 建構子");
    }
}

// 使用
Dog dog = new Dog("小黑", "柴犬");
// 輸出:
// Animal 建構子
// Dog 建構子

super() 的規則

  1. 必須是第一行
public Dog(String name, String breed) {
    System.out.println("開始");  // ✗ 編譯錯誤
    super(name);
}
  1. 預設呼叫無參數建構子

如果沒有明確呼叫,編譯器會自動加入 super()

class Animal {
    public Animal() {
        System.out.println("Animal 預設建構子");
    }
}

class Dog extends Animal {
    public Dog() {
        // 編譯器自動加入 super();
        System.out.println("Dog 建構子");
    }
}
  1. 父類別沒有無參數建構子時必須明確呼叫
class Animal {
    public Animal(String name) {  // 只有這個建構子
        this.name = name;
    }
}

class Dog extends Animal {
    public Dog() {
        // 編譯錯誤:父類別沒有無參數建構子
    }

    public Dog(String name) {
        super(name);  // ✓ 必須明確呼叫
    }
}

存取父類別方法

使用 super.method() 呼叫父類別的方法:

class Animal {
    public void speak() {
        System.out.println("動物發出聲音");
    }
}

class Dog extends Animal {
    @Override
    public void speak() {
        super.speak();  // 先呼叫父類別方法
        System.out.println("汪汪!");
    }
}

// 使用
Dog dog = new Dog();
dog.speak();
// 輸出:
// 動物發出聲音
// 汪汪!

實際應用:擴展功能

class Logger {
    public void log(String message) {
        System.out.println("[LOG] " + message);
    }
}

class TimestampLogger extends Logger {
    @Override
    public void log(String message) {
        String timestamp = java.time.LocalDateTime.now().toString();
        super.log(timestamp + " - " + message);  // 加入時間戳記後呼叫父類別方法
    }
}

存取父類別變數

當子類別有同名變數時,使用 super.variable 存取父類別變數:

class Parent {
    protected String message = "父類別訊息";
}

class Child extends Parent {
    private String message = "子類別訊息";

    public void show() {
        System.out.println(message);        // 子類別訊息
        System.out.println(this.message);   // 子類別訊息
        System.out.println(super.message);  // 父類別訊息
    }
}

注意:變數沒有覆寫的概念,子類別的同名變數會「隱藏」父類別的變數

建構子執行順序

建構子從最上層的父類別開始執行:

class Grandparent {
    public Grandparent() {
        System.out.println("1. Grandparent 建構子");
    }
}

class Parent extends Grandparent {
    public Parent() {
        System.out.println("2. Parent 建構子");
    }
}

class Child extends Parent {
    public Child() {
        System.out.println("3. Child 建構子");
    }
}

// 使用
new Child();
// 輸出:
// 1. Grandparent 建構子
// 2. Parent 建構子
// 3. Child 建構子

super 與 this 的比較

特性thissuper
代表當前物件父類別部分
呼叫建構子this()super()
存取變數this.varsuper.var
存取方法this.method()super.method()
可省略無衝突時可省略無衝突時可省略

不能同時使用

this()super() 不能同時出現在同一個建構子中:

public Dog(String name) {
    super(name);
    this();  // ✗ 編譯錯誤
}

正確做法是使用建構子鏈:

public Dog() {
    this("無名");  // 呼叫另一個建構子
}

public Dog(String name) {
    super(name);   // 該建構子呼叫父類別
}

多層繼承中的 super

super 只能存取直接父類別:

class A {
    protected void methodA() {
        System.out.println("A");
    }
}

class B extends A {
    @Override
    protected void methodA() {
        System.out.println("B");
    }
}

class C extends B {
    @Override
    protected void methodA() {
        super.methodA();  // 呼叫 B 的 methodA()
        // super.super.methodA();  // ✗ 無法直接存取 A
    }
}

實際範例

員工薪資系統

class Employee {
    protected String name;
    protected double baseSalary;

    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }

    public double calculateSalary() {
        return baseSalary;
    }
}

class Manager extends Employee {
    private double bonus;

    public Manager(String name, double baseSalary, double bonus) {
        super(name, baseSalary);  // 呼叫父類別建構子
        this.bonus = bonus;
    }

    @Override
    public double calculateSalary() {
        return super.calculateSalary() + bonus;  // 基本薪資 + 獎金
    }
}

class SalesEmployee extends Employee {
    private double commission;
    private int salesCount;

    public SalesEmployee(String name, double baseSalary, double commission) {
        super(name, baseSalary);
        this.commission = commission;
        this.salesCount = 0;
    }

    public void makeSale() {
        salesCount++;
    }

    @Override
    public double calculateSalary() {
        return super.calculateSalary() + (commission * salesCount);
    }
}

GUI 元件

class Component {
    protected int x, y, width, height;

    public Component(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public void draw() {
        System.out.println("繪製元件於 (" + x + ", " + y + ")");
    }
}

class Button extends Component {
    private String label;

    public Button(int x, int y, int width, int height, String label) {
        super(x, y, width, height);
        this.label = label;
    }

    @Override
    public void draw() {
        super.draw();  // 先執行父類別的繪製
        System.out.println("繪製按鈕文字:" + label);
    }
}

super 不能用的情況

靜態方法中不能使用

class Parent {
    protected int value = 10;
}

class Child extends Parent {
    public static void staticMethod() {
        // System.out.println(super.value);  // ✗ 編譯錯誤
    }
}

最頂層類別

Object 是所有類別的根,沒有父類別:

class MyClass {
    public void method() {
        super.toString();  // ✓ 呼叫 Object.toString()
        // super.super...   // 不存在更上層
    }
}

重點整理

  • super() 呼叫父類別建構子,必須是第一行
  • super.method() 呼叫父類別的方法
  • super.variable 存取父類別的變數
  • 建構子從最上層父類別開始執行
  • this()super() 不能同時使用
  • super 只能存取直接父類別
  • 靜態方法中不能使用 super