什麼是「繼承」
繼承是 Java 的物件導向三大特性之一,讓子類別(Subclass)可以**重複使用父類別(Superclass)**的屬性和方法,避免重複撰寫程式碼。
類別繼承關係
| 名稱 |
說明 |
關鍵字 |
範例 |
| 父類別(超類別) |
被繼承的類別 |
super |
class Animal {} |
| 子類別(衍生類別) |
繼承的類別 |
extends |
class Dog extends Animal {} |
基本語法:使用 extends
1 2 3 4 5 6 7 8 9 10 11 12
| class Animal { String name; void eat() { System.out.println(name + " 正在吃飯"); } }
class Dog extends Animal { void bark() { System.out.println(name + " 汪汪叫"); } }
|
1 2 3 4
| Dog d = new Dog(); d.name = "Bingo"; d.eat(); d.bark();
|
記憶體結構(Stack & Heap)
| 區域 |
儲存什麼 |
| Stack |
變數 d(記憶體位置) |
| Heap |
Dog 物件(有 Dog 和繼承自 Animal 的欄位與方法) |
方法覆寫(Override)
子類別可以改寫父類別的方法,稱為「覆寫」。
1 2 3 4 5 6 7 8 9 10 11 12
| class Animal { void eat() { System.out.println("正在吃飯"); } }
class Cat extends Animal { @Override void eat() { System.out.println("貓在吃魚"); } }
|
1 2
| Cat c = new Cat(); c.eat();
|
- 加上
@Override 註解可讓編譯器檢查是否正確覆寫
- 必須「方法名稱、參數、回傳型別」都一致!
super 關鍵字用法
super 表示「父類別(超類別)的參考」。
範例 1
| 用法 |
說明 |
範例 |
super.方法() |
呼叫父類別的方法 |
super.eat() |
super.屬性 |
存取父類別的變數 |
super.name |
super(...) |
呼叫父類別建構子 |
super("Bingo") |
1 2 3 4 5 6 7 8 9 10 11 12
| class Animal { String name; Animal(String name) { this.name = name; } }
class Dog extends Animal { Dog(String name) { super(name); } }
|
範例 2
| 用途 |
範例 |
解釋 |
| 呼叫父類別的建構子 |
super(); |
通常放在子類別建構子的第一行 |
| 呼叫父類別的方法 |
super.printInfo(); |
被子類別覆寫後仍可呼叫原方法 |
| 取得父類別的成員變數 |
super.name |
當子類別與父類別變數重名時使用 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class Person { String name = "Default";
public void printInfo() { System.out.println("Person: " + name); } }
class Student extends Person { String name = "Student";
public Student() { super(); }
public void printInfo() { super.printInfo(); System.out.println("Student: " + this.name); } }
public class Main { public static void main(String[] args) { Student s1 = new Student(); s1.printInfo();
System.out.println();
Person p1 = new Student(); p1.printInfo();
System.out.println();
Person p2 = new Person(); p2.printInfo(); } }
|
this vs super 對照表
| 比較項目 |
this(這個物件) |
super(父類別) |
| 基本用途 |
指向目前類別建立的物件 |
指向目前類別的父類別所建立的物件 |
| 變數使用 |
訪問目前類別的屬性,常用於參數與成員變數重名時(this.name = name;) |
訪問父類別的屬性(如:super.name) |
| 方法使用 |
呼叫同一類別中其他方法(如:this.printInfo()) |
呼叫父類別的方法(如:super.printInfo()) |
| 建構子使用 |
呼叫同一類別中的其他建構子(如:this("Tom");) |
呼叫父類別的建構子(如:super("Tom");) |
| 使用限制 |
只能用在方法或建構子中
this(...) 必須在建構子第一行 |
只能用在子類別中
super(...) 也必須在建構子第一行 |
| 是否能同時用 |
✅ 可以在同一方法或建構子中使用(但 this() 與 super() 不能同時存在建構子第一行) |
✅ 可以在方法中混用,但建構子中兩者不能同時用 |
| 常見用途 |
區分參數與成員變數 內部方法呼叫 建構子間呼叫 |
使用父類別成員(屬性與方法) 呼叫父類別建構子 |
| 隱含對象 |
當前子類別的物件實體 |
子類別中的父類別物件實體 |
常見錯誤
this() 與 super() 只能出現在建構子的第一行,不能同時存在。
- 混淆了
this.name 與 super.name:要看你是要指自己的變數還是繼承來的。
詳細說明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Person { String name = "PersonName"; }
class Student extends Person { String name = "StudentName";
public void printNames() { System.out.println("this.name: " + this.name); System.out.println("super.name: " + super.name); } }
public class Main { public static void main(String[] args) { Student s = new Student(); s.printNames(); } }
|
實作題範例
- 父類別為
Person,有屬性 name,方法 printInfo()。
- 子類別為
Student,有自己的 name 屬性,覆寫 printInfo() 方法,並使用 super 呼叫父類別的 printInfo()。
- 在
main() 方法中建立一個 Student 物件並呼叫 printInfo() 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Person { String name = "Default";
public void printInfo() { System.out.println("Person: " + name); } }
class Student extends Person { String name = "Student";
public void printInfo() { super.printInfo(); System.out.println("Student: " + this.name); } }
public class Main { public static void main(String[] args) { Student s = new Student(); s.printInfo(); } }
|
其它 - 回傳練習
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class Person { private String name; private Integer age;
public Person() { this("匿名", 18); }
public Person(Integer age) { this("匿名", age); }
public Person(String name) { this(name, 18); }
public Person(String name, Integer age) { this.name = name; this.age = age; }
public void printInfo() { System.out.println("姓名:" + name + ",年齡:" + age); }
public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person(25); Person p3 = new Person("小明"); Person p4 = new Person("小美", 20);
p1.printInfo(); p2.printInfo(); p3.printInfo(); p4.printInfo(); } }
|
錯誤觀念澄清
| ❌錯誤觀念 |
✅正確觀念 |
| Java 不支援繼承 |
Java 支援單一繼承 |
| 子類別無法使用父類方法 |
只要沒被 private 修飾都能繼承 |
| 父類別的建構子不會執行 |
子類別建構子會自動先呼叫父類別建構子 |
| 方法覆寫時,回傳型別可以不同 |
覆寫時方法簽章必須相同 |
重點整理
- 繼承讓子類別
extends 父類別,節省程式碼
- 子類別能使用父類別的屬性與方法
- 可以使用
@Override 改寫方法內容
super() 能呼叫父類別建構子與成員
- 只有單一繼承,但可用**介面(interface)**實現多型(多種行為)