在kotlin中被sealed关键字修饰的类就是密封类,当值只能从有限的集合(受限的层次结构)中包含一个类型时,将使用密封类。为了理解这个概念先举个栗子:
class Expr
class Const(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
fun eval(e: Expr): Int =
when (e) {
is Const -> e.value
is Sum -> eval(e.right) + eval(e.left)
else -> throw IllegalArgumentException("Unknown expression")
}
在上面的程序中,基类 Expr 有两个派生类 Const (表示一个数字)和 Sum (表示两个表达式的和)。在这里,必须使用 else 分支来处理when表达式中的默认条件。
现在,如果从Expr类派生一个新的子类,则编译器将不会检测到任何东西,因为 else 分支会对其进行处理,就会抛出"Unknown expression"异常而导致错误。
要解决此问题,可以使用密封类。 如前所述,密封类限制了创建子类的可能性。 而且,在when表达式中处理密封类的所有子类时,不必使用else分支:
sealed class Expr
class Const(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
object NotANumber : Expr()
fun eval(e: Expr): Int =
when (e) {
is Const -> e.value
is Sum -> eval(e.right) + eval(e.left)
is NotANumber -> java.lang.Double.NaN
}
而且密封类是抽象类,它无法被外部实例化,它的继承也会被限制,所有的实现都只能由其内部的子类去完成。
不同kotlin迭代版本中密封类的进化史:
https://blog.csdn.net/vitaviva/article/details/117938161
枚举和密封类之间的区别
枚举类和密封类非常相似,枚举类型的值集也像密封类一样受到限制;
他们的区别是,枚举只能有一个实例,而密封类的子类可以有多个实例,并且密封类的子类可以携带自己独有的状态参数以及行为方法来记录更多的实现信息以完成更多的功能,这是枚举类所不具备的。