1、声明密封类
声明一个密封类需要在类名前添加 sealed
修饰符。
2、什么是密封类
密闭类用来表示 受限 的 类继承 结构,什么意思?我们看一下官方的解释:当一个值为有限集中的类型(容易引起歧义-- 是有限 *集中*
还是 *有限集* 中
,在此处我认为是 有限集 中,但是我却在这里跳了坑)、而不能有任何其他类型。什么是有限集中?说实话看到这样的定义我还是不能理解到底什么是 密封类。看一下原文吧
Sealed classes are used for representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type. They are, in a sense, an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances which can contain state.
自己翻译一下,如下
当一个值可以为有限集合中的一个类型但不能是其他的类型时,密封类用来表示这种受限的类层次结构。在某种意义上,密封类是枚举类的扩展,对于一个枚举类来说它的值也是有限制的,而且每个枚举类常量只存在一个实例,但是密封类的子类可以拥有包含状态的多个实例。
个人理解的是枚举类和密封类的不同为: 密封类的有限集合的元素为 类型,而枚举类的有限集合为 值,两者所面向的维度是不同的。或者也可以这么说:密封类适用于子类可数的情况,枚举适用于实例可数的情况。
从上文我们知道密封类可以有子类,但是这是有限制的:密封类的子类只能定义在密封类的内部或同一个文件中,因为其构造方法为私有的
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
另外,密封类还有一些其他需要注意的点:
- 密封类自身是抽象的,无法直接实例化并可以有抽象成员
- 密封类不可以有非 private 构造函数(默认为 private)
- 扩展密封类子类的类可以放在任何处,不必非像其子类一样位于密封类的内部或者是在同一个文件中
3、密封类的使用
我们都知道在使用 when 表达式
作为表达式时 else 语句
不可缺少,而使用密封类的一个关键好处在 如果验证语句覆盖了所有情况,就不需要为该 when 表达式添加 else 语句 。
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}