类修饰符
上一章节讨论了Mixin 和 Mixin 类。 本章节将重点讨论类的修饰符及其组合:
abstract
abstract class 用于声明抽象类,抽象类可包含抽象方法(即只有签名没有具体实现的方法),且不能被实例化。
// ex447.dart
abstract class Mammal {
void breathe();
}
interface
使用 interface class 创建一个接口类(或简称接口),详见接口一节。
base
每个类(class)都隐式地定义了一个接口(interface),因而可以实现(implements)一个类(即实现类中的方法)。base 类为继承而生,在定义它的library之外,只能被继承,而不能被实现。
ex541.dart:
// ex541.dart
base class Vehicle { // 1
void moveForward(int meters) {
// ...
}
}
base class Car implements Vehicle { // 2
@override
void moveForward(int meters) {
// ...
}
}
base class Motorcycle extends Vehicle { // 3
}
ex541a.dart:
// ex541a.dart
import 'ex541.dart';
base class Truck extends Vehicle { // 4
int passengers = 4;
@override
void moveForward(int meters) {
// ...
}
}
// ERROR:
// The class 'Vehicle' can't be implemented outside of its library
// because it's a base class.
base class Train implements Vehicle { // 5
@override
void moveForward(int meters) {
// ...
}
}
ex541.dart文件中的Vehicle是一个base类,它有一个实例方法moveForward(int);- 同一文件中的
Car实现了Vehicle; - 同一文件中的
Motorcycle继承(extends)了Vehicle; - 另一文件(
ex541a.dart)中的Truck继承了Vehicle; - 另一文件(
ex541a.dart)中的Train试图实现Vehicle,引发编译错误。
base 类有如下特点:
base类的子类/实现类必须使用base或final或sealed修饰,这是为了确保base的语义;base类的子类自动继承了其可见的成员(字段/方法),因此为base类添加新的成员不会破坏子类,除非新成员与子类发生冲突;- 实例化
base类的子类,必然导致base类的构造函数被调用。
sealed
sealed class用于创建密封类。密封类的子类是可穷举的,且必须与密封类位于同一个libary里。密封类是隐式抽象的,不能被实例化。
// ex344.dart
import 'dart:math' as math;
sealed class Shape {}
class Square implements Shape {
final double length;
Square(this.length);
}
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => math.pi * r * r,
};
密封类的一个特点是switch详尽性检查。假如还有一个类也实现或继承了 Shape,如:
class Rectangle extends Shape {}
calculateArea(Shape)函数会有编译错误:
Error: The type 'Shape' is not exhaustively matched by the switch cases since it doesn't match 'Rectangle()'.
- 'Shape' is from 'bin/ch03/ex344.dart'.
Try adding a wildcard pattern or cases that match 'Rectangle()'.
double calculateArea(Shape shape) => switch (shape) {
^
final
final类不能被外部libary继承或实现。final类的子类或实现类也必须是final类。
ex542.dart
// ex542.dart
final class Pet {}
final class Kitty extends Pet {}
final class Garfield implements Pet {}
ex542a.dart
// ex542a.dart
import 'ex542.dart';
// Error: The class 'Pet' can't be extended outside of its library
// because it's a final class
final class Doggy extends Pet {}
// Error: The class 'Pet' can't be implemented outside of its library
// because it's a final class.
final class Corgi implements Pet {}
由于final类只能被同一个library中的类继承或实现:
- 你可以安全地对其进行修改;
- 也不用担心其实例方法被其它的library重写。
修饰符的组合
下表列出了有效的修饰符的组合及其特性。
| 声明 | 可实例化? | 可继承? | 可实现? | Mixin? | 可穷举? |
|---|---|---|---|---|---|
class | ✔️ | ✔️ | ✔️ | ||
base class | ✔️ | ✔️ | |||
interface class | ✔️ | ✔️ | |||
final class | ✔️ | ||||
sealed class | ✔️ | ||||
abstract class | ✔️ | ✔️ | |||
abstract base class | ✔️ | ||||
abstract interface class | ✔️ | ||||
abstract final class | |||||
mixin class | ✔️ | ✔️ | ✔️ | ✔️ | |
base mixin class | ✔️ | ✔️ | ✔️ | ||
abstract mixin class | ✔️ | ✔️ | ✔️ | ||
abstract base mixin class | ✔️ | ✔️ | |||
mixin | ✔️ | ✔️ | |||
base mixin | ✔️ |