English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Kotlin シールドクラス(Sealed)

在本文中,您将在示例的帮助下了解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 分支会对其进行处理,这可能会导致错误。 如果在添加新的子类时编译器发出错误,那就更好了。

要解决此问题,可以使用密封类。 如前所述,密封类限制了创建子类的可能性。 而且,当您在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です。

エnumとシールドクラスの違い

エnumクラスシールドクラスと非常に似ています。エnumの値の集合もシールドクラスのように制限されています。

唯一の違いは、エnumは一つのインスタンスしか持たないのに対して、シールドクラスのサブクラスは複数のインスタンスを持つことができます。