Java 入門指南
單元 10 - 物件導向程式設計
繼承 (inheritance) 是讓類別 (class) 能從已經定義好的類別擴充功能,多型 (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) 進行設定。
然後最後是 public 的 speak() 方法
public void speak() {
System.out.println("哈囉,我是" + this.name);
}
speak() 方法印出欄位 name , public 的成員在存取上完全沒有限制,因此 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 = "老鼠";
}
}
Elephant 及 Mouse 都繼承自 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 專案,然後再加入 Animal 、 Elephant 、 Mouse 等類別檔案。
首先引入 ArrayList 與 List
import java.util.ArrayList;
import java.util.List;
關鍵字 import 用來引入 Java API 中的類別,這裡 ArrayList 與 List 是在 java.util 之中,如果類別是在 java.lang ,例如 String 類別就不需要使用關鍵字 import 引入。
底下就用到這兩個類別
List<Animal> animal_list = new ArrayList<Animal>();
這裡 animal_list 是 List 型態, List 是 ArrayList 實作的介面, List 之後用角括弧圍住 Animal 型態名稱,這是設定 List 裡頭的元素必須是 Animal 或 Animal 的子類別。
等號右邊用關鍵字 new 建立 ArrayList 型態的物件,由於 ArrayList 實作 List 介面,因此 ArrayList 屬於 List 型態,這裡 ArrayList 後面也是用 角括弧圍住 Animal 型態名稱,表示 animal_list 包含的是 Animal 型態的物件。
角括弧的寫法是泛型 (generics) 程式設計的概念,也就是在定義時先不明確設定型態,由建立實體物件時再實際設定。
ArrayList 是類似陣列 (array) 的資料型態,相較陣列有更多好用的方法。
繼續用 add() 方法將 Animal 、 Elephant 、 Mouse 等物件加入 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();
}
這裡就用到了多型的觀念,由於 Elephant 跟 Mouse 兩個類別都繼承自 Animal 類別,因此在使用像是 ArrayList 的時候,就可以在宣告時用 Animal 替代 Elephant 或 Mouse 。
執行結果如下
哈囉,我是動物 |
哈囉,我是大象 |
哈囉,我是老鼠 |
其實繼承、多型、泛型等等的程式設計概念,真的要講清楚都是大部頭的書,這裡先了解程式碼中出現什麼是什麼概念就好了,下一個單元繼續介紹介面 (interface) 與套件。
相關教學影片
中英文術語對照 | |
---|---|
array | 陣列 |
class | 類別 |
constructor | 建構子 |
field | 屬性 |
generics | 泛型 |
inheritance | 繼承 |
interface | 介面 |
method | 方法 |
overloading | 多載 |
parameter | 參數 |
polymorphism | 多型 |
string | 字串 |
subclass | 子類別 |
superclass | 父類別 |
重點整理 |
---|
1. 繼承是子類別透過父類別得到擴充。 |
2. 多型是透過繼承關係,父類別當作眾多子類別的通用型態。 |
問題與討論 |
---|
1. 什麼是物件導向程式設計中的繼承?為什麼要有繼承機制? |
2. 什麼是物件導向程式設計中的多型?多型是一種什麼樣的特性? |
練習 |
---|
1. 建立一個專案 Exercise1001 ,將 Animal.java 拷貝到新專案裡,然後在 main() 中建立 Animal 物件並呼叫 speak() 方法。 |
2. 承上題,另建立一個專案 Exercise1002 ,新增兩種動物類別繼承 Animal 類別,然後放入 ArrayList 中,依序呼叫 speak() 方法。 |