繼承類 Extend a class
透過 extends 關鍵字,可以從父類(superclass / 超類)衍生出子類(subclass)
使用 super 關鍵字,就能在子類內呼叫父類的成員(方法、建構子等等)
class Television {
void turnOn() {
...
//父類方法內執行的程式碼
}
}
// SmartTelevision 是子類,Television 是父類
class SmartTelevision extends Television {
@override
void turnOn() {
super.turnOn(); // 呼叫父類的 turnOn 方法
//子類專屬程式碼
...
}
}Code language: Dart (dart)
舉例來說,一般電視做為父類,智慧電視就是子類,智慧電視繼承了一般電視的功能。
extends 還有另一種使用情境:泛型章節中與參數化型別相關的內容。
實際範例
class Television {
void turnOn() {
print("電視通電,輸出基礎畫面");
}
}
// SmartTelevision 是子類,Television 是父類
class SmartTelevision extends Television {
@override
void turnOn() {
super.turnOn(); // 呼叫父類 turnOn 方法
//子類專屬程式碼
print("智慧電視:啟動網路模組、載入智慧系統首頁");
}
}
void main() {
// 一般電視實體
Television normalTv = Television();
print("===== 一般電視開機 =====");
normalTv.turnOn();
// 智慧電視實體
SmartTelevision smartTv = SmartTelevision();
print("\n===== 智慧電視開機 =====");
smartTv.turnOn();
}Code language: Dart (dart)
執行結果
D:\dartdemo\firstdart>dart run
Building package executable... (1.4s)
Built firstdart:firstdart.
===== 一般電視開機 =====
電視通電,輸出基礎畫面
===== 智慧電視開機 =====
電視通電,輸出基礎畫面
覆寫成員 Overriding members
1. 可覆寫的項目
子類能夠覆寫:實體方法(包含運算子)、getter、setter。
2. @override 註解
用途:明確宣告此方法主動覆寫父類成員,由編譯器協助檢查語法規則。
class Television {
set contrast(int value) {}
}
class SmartTelevision extends Television {
@override //告訴編譯器,這個方法是子類覆寫父類
set contrast(num value) {}
}
Code language: JavaScript (javascript)
3. 覆寫必須遵守的規則
- 回傳型別:覆寫方法的回傳型別必須和父類方法一致,或是父類回傳型別的子型別。
- 參數型別:覆寫方法參數型別必須和父類參數型別相同,或是父類參數型別的父型別(範例
int→num,num 為 int 的父型別,屬合法寫法)。 - 位置參數數量:若被覆寫的方法有 n 個位置參數,覆寫的方法也必須具備 n 個位置參數。
- 泛型約束:泛型方法不能覆寫非泛型方法;非泛型方法也無法覆寫泛型方法。
4. covariant 關鍵字(型別縮限特殊情境)
標準規則不允許縮小參數型別(向下轉型可能在執行階段觸發型別錯誤);
如果開發者能夠保證不會產生型別錯誤,可在參數加上 covariant,實現參數型別縮限。
當你覆寫運算子 == 時,一定要同時覆寫 Object 的 hashCode getter。
noSuchMethod ()
1. 用途
當程式嘗試呼叫不存在的實體方法 / 實體變數時,可以覆寫 noSuchMethod() 進行攔截,自訂處理邏輯。
若沒有覆寫,存取不存在的成員時會直接拋出 NoSuchMethodError。
class A {
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ${invocation.memberName}');
}
}
Code language: JavaScript (javascript)
Invocation物件:儲存本次呼叫資訊(成員名稱、參數等等)
2. 能夠觸發尚未實作方法呼叫的兩個前提(滿足其一即可)
- 呼叫接收者的靜態型別為
dynamic; - 接收者靜態型別宣告了該未實作方法(可以是抽象方法),並且接收者的動態型別擁有和
Object內建版本相異的noSuchMethod()實作。
範例
class A {
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ${invocation.memberName}');
// 額外印出呼叫參數、呼叫類型,展示完整呼叫資訊
print('呼叫參數:${invocation.arguments}');
print('呼叫類型:${invocation.runtimeType}');
}
}
void main() {
A obj = A();
// 呼叫不存在方法,觸發 noSuchMethod
obj.hello("test", 123);
// 存取不存在屬性
obj.unknownValue;
}Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Failed to build firstdart:firstdart:
bin/firstdart.dart:6:30: Error: The getter 'arguments' isn't defined for the type 'Invocation'.
- 'Invocation' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'arguments'.
print('cal:${invocation.arguments}');
^^^^^^^^^
bin/firstdart.dart:14:7: Error: The method 'hello' isn't defined for the type 'A'.
- 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing method, or defining a method named 'hello'.
obj.hello("test", 123);
^^^^^
bin/firstdart.dart:16:7: Error: The getter 'unknownValue' isn't defined for the type 'A'.
- 'A' is from 'bin/firstdart.dart'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'unknownValue'.
obj.unknownValue;Code language: PHP (php)
類別繼承與成員覆寫
Previous: Method(方法)
Next: Mixins