Kotlin 中存在 sealed 关键字能够润饰 class 和 interface ,表明密封类和接口。主要是为了约束类的承继结构以达到对承继进行控制的意图。
**密封类的子类在编译时明确可知。在代码编译后,不会有其他的子类呈现。**例如,其他模块无法完成你界说的密封类。因此,每一个密封类实例的类型是有限的类型调集。密封接口及其完成也是如此:一旦编译了具有密封接口的模块,就不会呈现新的完成。
与枚举类的区别
在某种意义上,与枚举类相似:枚举类型的值的调集也会受到约束,但每个枚举常量仅作为单个实例存在,而密封类的子类能够有多个实例,每个实例都拥有自己的状况。
密封类本身是抽象的,不能直接实例化,能够有抽象成员。
子类的位置
密封类的直接子类和接口有必要生命在同一个包名下,他们可能是尖端或者嵌套在密封类内部,能够是内部的 interface
、 class
或 object
声明。
子类的可见性不受约束,密封类的子类有必要具有适宜的命名,他们不能是本地对象或匿名对象。
枚举类不能够承继自密封类(和其他类相同),但它们能够完成密封接口。
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 的解释性言语的特性。能够把子类视为一种偏向的父类型。