类修饰符
:::版本说明 除了 abstract
之外,类修饰符至少需要 3.0 的 语言版本 。 :::
类修饰符控制类或混入的使用方式,包括 在其自身库中 的使用方式以及在其定义库外部的使用方式。
修饰符关键字位于类或混入声明之前。例如,编写 abstract class
定义了一个抽象类。可以在类声明前出现的完整修饰符集包括:
abstract
base
final
interface
sealed
mixin
只有 base
修饰符可以出现在混入声明之前。修饰符不适用于其他声明,例如 enum
、 typedef
、 extension
或 extension type
。
在决定是否使用类修饰符时,请考虑类的预期用途以及类需要依赖的行为。
:::注意 如果您维护一个库,请阅读 面向 API 维护者的类修饰符 页面,了解如何为您的库处理这些更改的指导。 :::
无修饰符
#要允许从任何库无限制地构造或子类型化,请使用没有修饰符的 class
或 mixin
声明。默认情况下,您可以:
abstract
#要定义一个不需要对其整个接口进行完整、具体实现的类,请使用 abstract
修饰符。
抽象类不能从任何库(无论是其自身库还是外部库)构造。抽象类通常具有 抽象方法 。
abstract class Vehicle {
void moveForward(int meters);
}
import 'a.dart';
// 错误:无法构造。
Vehicle myVehicle = Vehicle();
// 可以扩展。
class Car extends Vehicle {
int passengers = 4;
@override
void moveForward(int meters) {
// ...
}
}
// 可以实现。
class MockVehicle implements Vehicle {
@override
void moveForward(int meters) {
// ...
}
}
如果您希望您的抽象类看起来可实例化,请定义一个 工厂构造函数 。
base
#要强制继承类或混入的实现,请使用 base
修饰符。基类不允许在其自身库之外进行实现。这保证了:
- 每当创建类的子类型的实例时,都会调用基类构造函数。
- 所有实现的私有成员都存在于子类型中。
base
类中新的实现成员不会破坏子类型,因为所有子类型都继承了新成员。- 只有当子类型已经声明了具有相同名称和不兼容签名的成员时,此情况才不成立。
您必须将实现或扩展基类的任何类标记为 base
、 final
或 sealed
。这可以防止外部库破坏基类保证。
base class Vehicle {
void moveForward(int meters) {
// ...
}
}
import 'a.dart';
// 可以构造。
Vehicle myVehicle = Vehicle();
// 可以扩展。
base class Car extends Vehicle {
int passengers = 4;
// ...
}
// 错误:无法实现。
base class MockVehicle implements Vehicle {
@override
void moveForward() {
// ...
}
}
interface
#要定义接口,请使用 interface
修饰符。接口自身定义库之外的库可以实现接口,但不能扩展它。这保证了:
- 当类的实例方法之一调用
this
上的另一个实例方法时,它将始终调用来自同一库的已知方法实现。 - 其他库不能覆盖接口类自身的方法以后可能以意外方式调用的方法。这减少了 脆弱基类问题 。
interface class Vehicle {
void moveForward(int meters) {
// ...
}
}
import 'a.dart';
// 可以构造。
Vehicle myVehicle = Vehicle();
// 错误:无法继承。
class Car extends Vehicle {
int passengers = 4;
// ...
}
// 可以实现。
class MockVehicle implements Vehicle {
@override
void moveForward(int meters) {
// ...
}
}
abstract interface
#interface
修饰符最常见的用途是定义纯接口。将 interface
和 abstract
修饰符组合用于 abstract interface class
。
与 interface
类一样,其他库可以实现但不能继承纯接口。与 abstract
类一样,纯接口可以具有抽象成员。
final
#要关闭类型层次结构,请使用 final
修饰符。这可以防止从当前库外部的类进行子类型化。禁止继承和实现完全禁止子类型化。这保证了:
- 您可以安全地向 API 添加增量更改。
- 您可以调用实例方法,同时知道它们没有在第三方子类中被覆盖。
最终类可以在同一库中扩展或实现。 final
修饰符包含 base
的效果,因此任何子类也必须标记为 base
、 final
或 sealed
。
final class Vehicle {
void moveForward(int meters) {
// ...
}
}
import 'a.dart';
// 可以构造。
Vehicle myVehicle = Vehicle();
// 错误:无法继承。
class Car extends Vehicle {
int passengers = 4;
// ...
}
class MockVehicle implements Vehicle {
// 错误:无法实现。
@override
void moveForward(int meters) {
// ...
}
}
sealed
#要创建已知的、可枚举的子类型集,请使用 sealed
修饰符。这允许您在这些子类型上创建一个 switch,该 switch 静态地保证是 详尽的 。
sealed
修饰符阻止从其自身库外部扩展或实现类。密封类隐式地是 抽象的 。
- 它们本身不能被构造。
- 它们可以具有 工厂构造函数 。
- 它们可以为其子类定义要使用的构造函数。
但是,密封类的子类并非隐式抽象。
编译器知道任何可能的直接子类型,因为它们只能存在于同一个库中。这允许编译器在 switch 没有穷举地处理其所有情况中的所有可能的子类型时向您发出警告:
sealed class Vehicle {}
class Car extends Vehicle {}
class Truck implements Vehicle {}
class Bicycle extends Vehicle {}
// 错误:无法实例化。
Vehicle myVehicle = Vehicle();
// 子类可以实例化。
Vehicle myCar = Car();
String getVehicleSound(Vehicle vehicle) {
// 错误:switch 缺少 Bicycle 子类型或默认情况。
return switch (vehicle) {
Car() => 'vroom',
Truck() => 'VROOOOMM',
};
}
如果您不希望 详尽的切换 ,或者希望以后能够添加子类型而不会破坏 API,请使用 final
修饰符。有关更深入的比较,请阅读 sealed
与 final
。
组合修饰符
#您可以组合一些修饰符以进行分层限制。类声明可以按顺序为:
- (可选)
abstract
,描述类是否可以包含抽象成员并阻止实例化。 - (可选)
base
、interface
、final
或sealed
之一,描述对其他库子类型化类的限制。 - (可选)
mixin
,描述声明是否可以混入。 class
关键字本身。
您不能组合某些修饰符,因为它们是矛盾的、冗余的或相互排斥的:
有关如何组合类修饰符的更多指导,请查看 类修饰符参考 。
除非另有说明,否则本网站上的文档反映的是 Dart 3.6.0。页面最后更新于 2025-02-05。 查看源代码 或 报告问题.