继承类 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