Kotlin 密封类

密封类用于当一个值只能是有限集合中的一个类型时(受限的层次结构)。


在详细介绍密封类之前,让我们先了解一下它们解决了什么问题。我们来看一个例子(摘自 Kotlin 官方网站 -密封类文章)

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(表示两个表达式的和)。在这里,在when 表达式中使用 else 分支作为默认条件是强制性的。

现在,如果您从 Expr 类派生出一个新的子类,编译器将不会检测到任何内容,因为 else 分支会处理它,这可能导致错误。如果我们添加一个新的子类,编译器能发出错误该多好。

为了解决这个问题,您可以使用密封类。如前所述,密封类限制了创建子类的可能性。而且,当您在 when 表达式中处理密封类的所有子类时,就不需要使用 else 分支了。


要创建密封类,需要使用 sealed 修饰符。例如:

sealed class Expr

示例:密封类

您可以使用密封类来解决上述问题:

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)
            NotANumber -> java.lang.Double.NaN
        }

如您所见,没有 else 分支。如果您从 Expr 类派生出一个新的子类,除非在 when 表达式中处理了该子类,否则编译器会报错。


几点重要说明

  • 密封类的所有子类都必须在声明密封类的同一文件中声明。
  • 密封类本身是抽象的,您无法从中实例化对象。
  • 您不能为密封类创建非私有构造函数;它们的构造函数默认是 private 的。

枚举类和密封类之间的区别

枚举类和密封类非常相似。枚举类型的取值集合也像密封类一样受到限制。

唯一的区别是,枚举只能有一个实例,而密封类的子类可以有多个实例。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战