类修饰符,除了 abstract ,需要 至少为 3.0 的语言版本。
类修饰符控制类或 mixin 的使用方式,既可以在其自己的库内使用,也可以从库外部使用。 它被定义了。
修饰符关键字位于类或 mixin 声明之前。 例如,写作定义了一个抽象类。 可以在类声明之前出现的完整修饰符集包括:abstract class
- abstract
- base
- final
- interface
- sealed
- mixin
只有修饰符可以出现在 mixin 声明之前。修饰符确实如此 不适用于其他声明,如 、 或 。baseenumtypedefextension
在决定是否使用类修饰符时,请考虑 类,以及类需要能够依赖哪些行为。
如果您维护库,请阅读 API 维护人员的类修饰符页面,以获取有关如何为库导航这些更改的指导。
无修饰符
要允许不受限制地允许从任何库构造或子类型, 使用不带修饰符的 OR 声明。默认情况下,您可以:classmixin
- 构造类的新实例。
- 扩展类以创建新的子类型。
- 实现类或 mixin 的接口。
- 在 mixin 或 mixin 类中混音。
abstract
定义一个不需要其完整、具体实现的类 整个界面,请使用修饰符。abstract
抽象类不能从任何库构造,无论是它自己的还是 一个外部图书馆。抽象类通常具有抽象方法。
// Library a.dart
abstract class Vehicle {
void moveForward(int meters);
}
// Library b.dart
import 'a.dart';
// Error: Cannot be constructed
Vehicle myVehicle = Vehicle();
// Can be extended
class Car extends Vehicle {
int passengers = 4;
// ···
}
// Can be implemented
class MockVehicle implements Vehicle {
@override
void moveForward(int meters) {
// ...
}
}
如果你希望你的抽象类看起来是可实例化的, 定义工厂构造函数。
base
要强制继承类或 mixin 的实现,请使用修饰符。 基类不允许在其自己的库之外实现。这保证了:base
- 每当 类已创建。
- 所有已实现的私有成员都存在于子类型中。
- 类中新实现的成员不会中断子类型, 因为所有子类型都继承了新成员。base
- 除非子类型已声明具有相同名称的成员,否则为 true。 和不兼容的签名。
必须将实现或扩展基类的任何类标记为 、 或 。这样可以防止外部库 破坏基类保证。basefinalsealed
// Library a.dart
base class Vehicle {
void moveForward(int meters) {
// ...
}
}
// Library b.dart
import 'a.dart';
// Can be constructed
Vehicle myVehicle = Vehicle();
// Can be extended
base class Car extends Vehicle {
int passengers = 4;
// ...
}
// ERROR: Cannot be implemented
base class MockVehicle implements Vehicle {
@override
void moveForward() {
// ...
}
}
interface
若要定义接口,请使用修饰符。之外的库 接口自己的定义库可以实现接口,但不能扩展它。 这保证了:interface
当类的一个实例方法调用另一个实例方法时, 它将始终从同一库调用该方法的已知实现。this 其他库无法重写接口的方法 类自己的方法以后可能会以意想不到的方式调用。 这减少了脆弱的基类问题。
// Library a.dart
interface class Vehicle {
void moveForward(int meters) {
// ...
}
}
// Library b.dart
import 'a.dart';
// Can be constructed
Vehicle myVehicle = Vehicle();
// ERROR: Cannot be inherited
class Car extends Vehicle {
int passengers = 4;
// ...
}
// Can be implemented
class MockVehicle implements Vehicle {
@override
void moveForward(int meters) {
// ...
}
}
abstract interface
修饰符最常见的用途是定义纯接口。组合 和 abstract 修饰符。interfaceinterfaceabstract interface class
像类一样,其他库可以实现,但不能继承, 一个纯粹的界面。像类一样,纯接口可以有 抽象成员。interfaceabstract
final
若要关闭类型层次结构,请使用修饰符。 这样可以防止从当前库之外的类进行子类型化。 不允许继承和实现会完全阻止子类型化。 这保证了:final
- 您可以安全地向 API 添加增量更改。
- 您可以调用实例方法,因为它们尚未在 第三方子类。
最终类可以在 同一个库。修饰符包含 和 的效果 因此,任何子类也必须标记为 、 或 。finalbasebasefinalsealed
// Library a.dart
final class Vehicle {
void moveForward(int meters) {
// ...
}
}
// Library b.dart
import 'a.dart';
// Can be constructed
Vehicle myVehicle = Vehicle();
// ERROR: Cannot be inherited
class Car extends Vehicle {
int passengers = 4;
// ...
}
class MockVehicle implements Vehicle {
// ERROR: Cannot be implemented
@override
void moveForward(int meters) {
// ...
}
}
sealed
若要创建一组已知的、可枚举的子类型,请使用修饰符。 这允许您创建静态确保的子类型的切换 详尽无遗。sealed
修饰符阻止扩展类或 在自己的库之外实现。密封类是隐式抽象的。sealed
- 它们不能自己建造。
- 它们可以有工厂构造函数。
- 它们可以定义构造函数供其子类使用。
然而,密封类的子类并不是隐含的抽象。
编译器知道任何可能的直接子类型 因为它们只能存在于同一个库中。 这允许编译器在开关不 详尽地处理所有可能的亚型:
sealed class Vehicle {}
class Car extends Vehicle {}
class Truck implements Vehicle {}
class Bicycle extends Vehicle {}
// ERROR: Cannot be instantiated
Vehicle myVehicle = Vehicle();
// Subclasses can be instantiated
Vehicle myCar = Car();
String getVehicleSound(Vehicle vehicle) {
// ERROR: The switch is missing the Bicycle subtype or a default case.
return switch (vehicle) {
Car() => 'vroom',
Truck() => 'VROOOOMM',
};
}
如果您不想进行详尽的切换, 或者希望以后能够在不破坏 API 的情况下添加子类型, 使用 final 修饰符。为了进行更深入的比较, 阅读密封版与最终版。
组合修饰符
您可以组合一些修饰符以实现分层限制。 类声明可以按顺序:
- (可选) ,描述类是否可以包含抽象成员 并防止实例化。abstract
- (可选)、 或 之一,描述 对子类型化类的其他库的限制。baseinterfacefinalsealed
- (可选),描述声明是否可以混入。mixin
- 关键字本身。class
您不能组合某些修饰符,因为它们是矛盾的、多余的或 否则互斥:
- abstract跟。密封类始终是隐式抽象的。sealed
- interface或 .这些访问修饰符 防止混入。finalsealedmixin 有关完整指导,请参阅类修饰符参考。