Java 入門指南

單元 10 - 物件導向程式設計

~~學習進度表~~

繼承 (inheritance) 是讓類別 (class) 能從已經定義好的類別擴充功能,多型 (polymorphism) 則是讓物件在繼承關係之下,讓物件的型態可以有通用性

Inheritance ↔ Polymorphism

「繼承」的英文動詞原文為 inherit ,程式設計社群長久以來都翻譯成「繼承」,這裡沿用社群的習慣。然而「繼承」的中文隱含上一代死去,下一代得到上一代的東西、權利的意思,英文 inherit 卻是泛指什麼得到什麼,因此遺傳也可以用 inherit ,物件導向中的「繼承」比較接近遺傳的意思,因為程式執行的當下,父、子物件都是並存的。

繼承的寫法是在類別名稱用關鍵字 extends ,之後再接所繼承的類別名稱,例如

public class Elephant extends Animal {

這樣 Elephant 類別就繼承了 Animal 類別。

在繼承關係中,繼承自其他類別的類別稱之為子類別 (subclass) ,像是 Elephant 就是 Animal 的子類別,而被繼承的類別稱之為父類別 (superclass) ,像是 Animal 就是 Elephant 的父類別。

以下為 Animal 類別的完整程式碼

/*
 * 檔名:Animal.java
 * 作者:張凱慶
 * 網站:http://kaiching.org
 */
package classdemo06;

public class Animal {
    protected String name;
    
    public Animal() {
        this.name = "動物";
    }

    public Animal(String s) {
        this.name = s;
    }

    public void speak() {
        System.out.println("哈囉,我是" + this.name);
    }
}

裡頭定義一個 protected 屬性 (field) ,字串 (string) name

protected String name;

這裡 protected 的屬性可以被子類別繼承, private 則不行。

下面定義兩個 public 的建構子 (constructor)

public Animal() {
    this.name = "動物";
}

public Animal(String s) {
    this.name = s;
}

這叫做多載 (overloading) ,建構子可以多載,方法 (method) 也可以多載,多載是指可以提供不同參數列給相同名稱的建構子或方法,使得呼叫的時候可以用不同的參數 (parameter) 進行設定。

然後最後是 publicspeak() 方法

public void speak() {
    System.out.println("哈囉,我是" + this.name);
}

speak() 方法印出欄位 namepublic 的成員在存取上完全沒有限制,因此 public 都會被子類別繼承。

以下是子類別 Elephant

/*
 * 檔名:Elephant.java
 * 作者:張凱慶
 * 網站:http://kaiching.org
 */
package classdemo06;

public class Elephant extends Animal {
    public Elephant() {
        this.name = "大象";
    }
}

另一個子類別 Mouse

/*
 * 檔名:Mouse.java
 * 作者:張凱慶
 * 網站:http://kaiching.org
 */
package classdemo06;

public class Mouse extends Animal {
    public Mouse() {
        this.name = "老鼠";
    }
}

ElephantMouse 都繼承自 Animal ,這裡只有定義兩者各自的建構子, Elephant()name 設定為 "大象"Mouse() 則是設定為 "老鼠"

然後執行部分放在 ClassDemo06 類別

/*
 * 檔名:ClassDemo06.java
 * 作者:張凱慶
 * 網站:http://kaiching.org
 */
package classdemo06;

import java.util.ArrayList;
import java.util.List;

public class ClassDemo06 {
    public static void main(String[] args) {
        List<Animal> animal_list = new ArrayList<Animal>();
        animal_list.add(new Animal());
        animal_list.add(new Elephant());
        animal_list.add(new Mouse());
        for (Animal item:animal_list) {
            item.speak();
        }
    }
}

注意這個專案是先在 NetBeans 建立 ClassDemo06 專案,然後再加入 AnimalElephantMouse 等類別檔案。

首先引入 ArrayListList

import java.util.ArrayList;
import java.util.List;

關鍵字 import 用來引入 Java API 中的類別,這裡 ArrayListList 是在 java.util 之中,如果類別是在 java.lang ,例如 String 類別就不需要使用關鍵字 import 引入。

底下就用到這兩個類別

List<Animal> animal_list = new ArrayList<Animal>();

這裡 animal_listList 型態, ListArrayList 實作的介面, List 之後用角括弧圍住 Animal 型態名稱,這是設定 List 裡頭的元素必須是 AnimalAnimal 的子類別。

等號右邊用關鍵字 new 建立 ArrayList 型態的物件,由於 ArrayList 實作 List 介面,因此 ArrayList 屬於 List 型態,這裡 ArrayList 後面也是用 角括弧圍住 Animal 型態名稱,表示 animal_list 包含的是 Animal 型態的物件。

角括弧的寫法是泛型 (generics) 程式設計的概念,也就是在定義時先不明確設定型態,由建立實體物件時再實際設定。

ArrayList 是類似陣列 (array) 的資料型態,相較陣列有更多好用的方法。

繼續用 add() 方法將 AnimalElephantMouse 等物件加入 animal_list

animal_list.add(new Animal());
animal_list.add(new Elephant());
animal_list.add(new Mouse());

最後用 for 迴圈呼叫每一個物件的 speak() 方法

for (Animal item:animal_list) {
    item.speak();
}

這裡就用到了多型的觀念,由於 ElephantMouse 兩個類別都繼承自 Animal 類別,因此在使用像是 ArrayList 的時候,就可以在宣告時用 Animal 替代 ElephantMouse

執行結果如下

哈囉,我是動物
哈囉,我是大象
哈囉,我是老鼠

其實繼承、多型、泛型等等的程式設計概念,真的要講清楚都是大部頭的書,這裡先了解程式碼中出現什麼是什麼概念就好了,下一個單元繼續介紹介面 (interface) 與套件。

相關教學影片

上一頁 單元 9 - 封裝與建構子
回 Java 入門指南首頁
下一頁 單元 11 - 介面與套件
回 Java 教材首頁
回程式語言教材首頁
中英文術語對照
array陣列
class類別
constructor建構子
field屬性
generics泛型
inheritance繼承
interface介面
method方法
overloading多載
parameter參數
polymorphism多型
string字串
subclass子類別
superclass父類別
參考資料
1. The Java™ Tutorials: Inheritance
2. The Java™ Tutorials: Multiple Inheritance of State, Implementation, and Type
3. The Java™ Tutorials: Overriding and Hiding Methods
4. The Java™ Tutorials: Polymorphism
5. The Java™ Tutorials: Why Use Generics?
6. The Java™ Tutorials: Generic Types
7. The Java™ Tutorials: Raw Types
8. The Java™ Tutorials: Generic Methods
重點整理
1. 繼承是子類別透過父類別得到擴充。
2. 多型是透過繼承關係,父類別當作眾多子類別的通用型態。
問題與討論
1. 什麼是物件導向程式設計中的繼承?為什麼要有繼承機制?
2. 什麼是物件導向程式設計中的多型?多型是一種什麼樣的特性?
練習
1. 建立一個專案 Exercise1001 ,將 Animal.java 拷貝到新專案裡,然後在 main() 中建立 Animal 物件並呼叫 speak() 方法。
2. 承上題,另建立一個專案 Exercise1002 ,新增兩種動物類別繼承 Animal 類別,然後放入 ArrayList 中,依序呼叫 speak() 方法。