昨天學習了 Java 物件導向中的 Encapsulation(封裝),利用 private、Getter 和 Setter 保護消費資料。
今天繼續學習另一個物件導向的重要觀念:Inheritance(繼承)。
目前所有消費都是使用同一個 Expense 類別,但實際記帳時會有很多不同類型,例如飲食、交通、購物等。這些消費都有共同的「項目」和「金額」,但不同類型也可能有自己的資料。
這時候就可以使用「繼承」。
什麼是 Inheritance?
Inheritance 可以讓一個新的 Class 使用另一個 Class 已經擁有的內容。
例如我們原本有:
class Expense {
private String item;
private int amount;
}
現在想建立一個專門記錄飲食的類別:
class FoodExpense extends Expense {
}
這裡最重要的是:
extends Expense
意思就是 FoodExpense 繼承 Expense。
可以簡單理解成:
Expense
│
├── FoodExpense
│
└── TransportationExpense
Expense 是比較一般的消費,而下面可以再建立不同種類的消費。
父類別和子類別
今天還會遇到兩個新的名稱:
Expense 稱為 父類別(Superclass)。
FoodExpense 稱為 子類別(Subclass)。
例如:
class FoodExpense extends Expense {
}
可以理解成:
FoodExpense 是一種 Expense。
飲食消費本來就是消費的一種,所以可以使用 Expense 原本就有的項目和金額。
建立 Expense 父類別
先建立我們原本的 Expense:
class Expense {
private String item;
private int amount;
Expense(String item, int amount) {
this.item = item;
this.amount = amount;
}
public String getItem() {
return item;
}
public int getAmount() {
return amount;
}
}
這裡保存所有消費都會有的:
item
amount
建立 FoodExpense
接著建立飲食消費:
class FoodExpense extends Expense {
private String mealType;
FoodExpense(String item, int amount, String mealType) {
super(item, amount);
this.mealType = mealType;
}
public String getMealType() {
return mealType;
}
}
這次多了一個:
private String mealType;
用來記錄:
早餐
午餐
晚餐
所以一筆 FoodExpense 可以包含:
項目:牛肉麵
金額:150
餐別:午餐
super 是什麼?
今天另外出現:
super(item, amount);
super 可以用來呼叫父類別的 Constructor。
例如:
FoodExpense food =
new FoodExpense("牛肉麵", 150, "午餐");
其中:
牛肉麵
150
會透過:
super(item, amount);
交給 Expense。
而:
午餐
則由 FoodExpense 自己保存。
可以簡單想成:
FoodExpense
│
├── Expense 負責
│ ├── 牛肉麵
│ └── 150 元
│
└── FoodExpense 自己負責
└── 午餐
再建立 TransportationExpense
除了飲食,也可以建立交通消費:
class TransportationExpense extends Expense {
private String transportType;
TransportationExpense(
String item,
int amount,
String transportType
) {
super(item, amount);
this.transportType = transportType;
}
public String getTransportType() {
return transportType;
}
}
例如:
TransportationExpense transport =
new TransportationExpense("上學", 30, "捷運");
就代表:
項目:上學
金額:30 元
交通方式:捷運
今天的小實作
今天先做一個簡單版本,看看繼承實際使用起來是什麼樣子。
class Expense {
private String item;
private int amount;
Expense(String item, int amount) {
this.item = item;
this.amount = amount;
}
public String getItem() {
return item;
}
public int getAmount() {
return amount;
}
}
class FoodExpense extends Expense {
private String mealType;
FoodExpense(String item, int amount, String mealType) {
super(item, amount);
this.mealType = mealType;
}
public String getMealType() {
return mealType;
}
}
class TransportationExpense extends Expense {
private String transportType;
TransportationExpense(
String item,
int amount,
String transportType
) {
super(item, amount);
this.transportType = transportType;
}
public String getTransportType() {
return transportType;
}
}
public class Main {
public static void main(String[] args) {
FoodExpense food =
new FoodExpense("牛肉麵", 150, "午餐");
TransportationExpense transport =
new TransportationExpense("上學", 30, "捷運");
System.out.println("===== 飲食消費 =====");
System.out.println("項目:" + food.getItem());
System.out.println("金額:" + food.getAmount() + " 元");
System.out.println("餐別:" + food.getMealType());
System.out.println();
System.out.println("===== 交通消費 =====");
System.out.println("項目:" + transport.getItem());
System.out.println("金額:" + transport.getAmount() + " 元");
System.out.println(
"交通方式:" + transport.getTransportType()
);
}
}
執行結果
===== 飲食消費 =====
項目:牛肉麵
金額:150 元
餐別:午餐
===== 交通消費 =====
項目:上學
金額:30 元
交通方式:捷運
雖然 FoodExpense 裡面沒有重新寫:
getItem()
getAmount()
但是因為它:
extends Expense
所以可以直接使用從 Expense 繼承下來的方法。
這就是繼承很方便的地方。
為什麼不全部寫在同一個 Class?
如果不用繼承,我可能要分別寫:
FoodExpense
→ item
→ amount
→ mealType
TransportationExpense
→ item
→ amount
→ transportType
這樣 item 和 amount 就一直重複。
使用繼承之後,可以把共同內容放在:
Expense
→ item
→ amount
不同類型再增加自己的內容:
FoodExpense
→ mealType
TransportationExpense
→ transportType
這樣程式的結構會比較清楚,也可以減少重複的程式碼。
今天怎麼記 Inheritance?
我覺得今天最重要的是先記住:
extends
就是「繼承」。
例如:
class FoodExpense extends Expense
可以直接理解成:
FoodExpense 是 Expense 的一種。
而:
super(item, amount);
則是把資料交給父類別的 Constructor 處理。
所以今天可以先記成:
Expense(父類別)
↓ extends
FoodExpense(子類別)
super()
↓
呼叫父類別的 Constructor
Day 14 學習心得
今天學習了 Java 物件導向中的 Inheritance 繼承。剛開始看到父類別、子類別、extends 和 super 覺得有點複雜,但把它套用在記帳系統之後就比較容易理解。
不同類型的消費其實都有共同的項目和金額,所以可以先放在 Expense 裡,再讓飲食或交通消費繼承它,增加自己需要的資料。
我覺得繼承最大的好處是可以減少重複的程式碼,也讓不同類別之間的關係比較清楚。到今天為止,已經連續學習了 Class、Object、Constructor、Encapsulation 和 Inheritance,對 Java 的物件導向也比一開始更有概念。