
🚨 前言
sealed class 以及 1.5 里新增的 sealed interface 可谓是 Kotlin 语言的一大特色,其在类型判断、扩展和实现的限制场景里非常好用。
本文将从特点、场景和原理等角度综合分析 sealed 语法。
- Sealed Class
- Sealed Interface
- Sealed Class & Interface VS Enum
- Sealed Class VS Interface
🏁 Sealed Class
sealed class,密封类。具备最重要的一个特点:
- 其子类可以出现在定义 sealed class 的不同文件中,但不允许出现在与不同的
module中,且需要保证package一致
这样既可以避免 sealed class 文件过于庞大,又可以确保第三方库无法扩展你定义的 sealed class,达到限制类的扩展目的。事实上在早期版本中,只允许在 sealed class 内部或定义的同文件内扩展子类,这些限制在 Kotlin 1.5 中被逐步放开。
如果在不同 module 或 package 中扩展子类的话,IDE 会显示如下的提示和编译错误:
Inheritor of sealed class or interface declared in package xxx but it must be in package xxx where base class is declared
sealed class 还具有如下特点或限制:
-
sealed class 是抽象类,可以拥有抽象方法,无法直接实例化。否则,编译器将提示如下:
Sealed types cannot be instantiated
-
sealed class 的构造函数只能拥有两种可见性:默认情况下是
protected,还可以指定成 private,public 是不被允许的。Constructor must be private or protected in sealed class
-
sealed class 子类可扩展局部以及匿名类以外的任意类型子类,包括普通 class、
data class、object、sealed class 等,子类信息在编译期可知。假使匿名类扩展自 sealed class 的话,会弹出错误提示:
This type is sealed, so it can be inherited by only its own nested classes or objects
-
sealed class 的实例,可配合
when表达式进行判断,当所有类型覆盖后可以省略else分支如果没有覆盖所有类型,也没有 else 统筹则会发生编译警告或错误
1.7 以前:
Non-exhaustive ‘when’ statements on sealed class/interface will be prohibited in 1.7.
1.7 及以后:
‘when’ expression must be exhaustive, add …
当 sealed class 没有指定构造方法或定义任意属性的时候,建议子类定义成单例,因为即便实例化成多个实例,互相之间没有状态的区别:
‘sealed’ subclass has no state and no overridden ‘equals()’
下面结合代码看下 sealed class 的使用和原理:
示例代码:
// TestSealed.kt
sealed class GameAction(times: Int) {
// Inner of Sealed Class
object Start : GameAction(1)
data class AutoTick(val time: Int) : GameAction(2)
class Exit : GameAction(3)
}
除了在 sealed class 内嵌套子类外,还可以在外部扩展子类:
// TestSealed.kt
sealed class GameAction(times: Int) {
...
}
// Outer of Sealed Class
object Restart : GameAction(4)
除了可以在同文件下 sealed class 外扩展子类外,还可以在同包名不同文件下扩展。
// TestExtendedSealedClass.kt
// Outer of Sealed Class file
class TestExtendedSealedClass: GameAction(5)
对于不同类型的扩展子类,when 表达式的判断亦不同:
- 判断 sealed class 内部子类类型自然需要指定父类前缀
- object class 的话可以直接进行实例判断,也可以用
is关键字判断类型匹配 - 普通 class 类型的话则必须加上 is 关键字
- 判断 sealed class 外部子类类型自然无需指定前缀
class TestSealed {
fun test(gameAction: GameAction) {
when (gameAction) {
GameAction.Start -> {
}
// is GameAction.Start -> {}
is GameAction.AutoTick -> {
}

本文从特点、场景和原理等角度综合分析了Kotlin语言的sealed class和sealed interface。sealed class可限制类的扩展,其子类有特定的定义规则;sealed interface和sealed class特点相近,还能帮助实现多继承和扩展性。文章还对比了它们与枚举、接口的区别。
最低0.47元/天 解锁文章
1832

被折叠的 条评论
为什么被折叠?



