Kotlin 中存在 sealed 关键字能够润饰 class 和 interface ,表明密封类和接口。主要是为了约束类的承继结构以达到对承继进行控制的意图。

**密封类的子类在编译时明确可知。在代码编译后,不会有其他的子类呈现。**例如,其他模块无法完成你界说的密封类。因此,每一个密封类实例的类型是有限的类型调集。密封接口及其完成也是如此:一旦编译了具有密封接口的模块,就不会呈现新的完成。

与枚举类的区别

在某种意义上,与枚举类相似:枚举类型的值的调集也会受到约束,但每个枚举常量仅作为单个实例存在,而密封类的子类能够有多个实例,每个实例都拥有自己的状况。

密封类本身是抽象的,不能直接实例化,能够有抽象成员。

子类的位置

密封类的直接子类和接口有必要生命在同一个包名下,他们可能是尖端或者嵌套在密封类内部,能够是内部的 interfaceclassobject 声明。

子类的可见性不受约束,密封类的子类有必要具有适宜的命名,他们不能是本地对象或匿名对象。

枚举类不能够承继自密封类(和其他类相同),但它们能够完成密封接口。

1.4 版本 interface 不可用 sealed 关键字润饰,但 1.5 支撑了密封接口。

Sealed Interface

有时,咱们尽管对外暴露了 interface,可是并不希望外界去完成它。此刻就能够经过 Sealed Interface 去完成。

**枚举类完成 Sealed Interface 的作用是打破单承继约束。**举例说明,下面是一个枚举类,和它的反编译后的代码:

enum class JvmLang {
    Java, Kotlin, Scala
}
// 反编译
public final class JvmLang extends Enum{
    private JvmLang(String s,int i){
        super(s,i);
    }
    public static final JvmLang Java;
    public static final JvmLang Kotlin;
    public static final JvmLang Scala;
    ...
    static{
        Java = new Action("Java",0);
        Kotlin = new Action("Kotlin",1);
        Scala = new Action("Scala",2);
    }
}

由于单承继的约束,枚举类无法承继 Enum 以外的其他类,但有时候咱们又需求将其进行分类,例如分为 高档言语 和 机器言语:

sealed interface Language
enum class HighLevelLang : Language {
    Java, Kotlin, CPP
}
enum class MachineLang : Language {
    ARM, X86
}
object AssemblyLang : Language

经过密封类打破单类型的约束

咱们都知道 Java 言语中,承继联系只能有一个父类。

sealed class JvmLang {
    object Java : JvmLang()
    object Kotlin : JvmLang()
    object Groovy : JvmLang()
}
sealed class CompiledLang {
    object Java : CompiledLang()
    object Kotlin : CompiledLang()
    object Groovy : CompiledLang()
    object Cpp : CompiledLang()
}
// JvmLang 实际上是编译言语的一种
sealed class JvmLang : CompiledLang
object Java : JvmLang()
object Kotlin : JvmLang()
object Groovy : JvmLang()
object Cpp : CompiledLang()

以上的比如说明晰, Java 能够同时被视为 JvmLang 也可当成 CompiledLang 。 相似 Groovy 的解释性言语的特性。能够把子类视为一种偏向的父类型。