对比Java学Kotlin密封类

Posted 陈蒙_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对比Java学Kotlin密封类相关的知识,希望对你有一定的参考价值。

从 Java SE 15 开始,Java 也支持密封类了。

什么是密封类?

在 Kotlin 中类修饰符除了 open、abstract、data 这些,还有一个 sealed:

sealed interface Error // 注意,sealed 在 Kotlin 1.5 版本后才支持修饰 interface
sealed class IOError: Error 
    constructor()  /*...*/  // protected by default
    private constructor(description: String): this()  /*...*/  // private is OK
    // public constructor(code: Int): this()  // Error: public and internal are not allowed


class FileReadError(val f: File): IOError 
open class DatabaseError(val db: DataSource): IOError 
object RuntimeError: Error

首先密封类是类(或接口,以下统称为类),但是比普通的类多了一些限制,主要表现在继承关系上:

  • 密封类的直接子类必须要跟父类在同一个包内,具体形式可以是在 top-level 的单个文件,也可以是嵌套类;
  • 密封类的子类类型在编译时就已经完全确定,密封类所在包之外的使用方无法继承密封类新建其他的子类,对于密封类的孙子类则没有这个限制;
  • 密封类的子类的可见性修饰符跟普通类没有区别;
  • 同时,密封类天生是 abstract 的,里面可以有 abstract 方法,同时遵循抽象类的约束无法直接创建实例;
  • 密封类可以有构造函数,但是构造函数的修饰符只能是 private 或 protected;

有什么作用?

由于密封类所有的子类型都是已知的,所以密封类一般用在“状态机”场景中,比如枚举错误类型、网络请求的结果类型、列表中的数据类型等。
特别是跟 when 关键字结合使用,口味更加哦,因为:

  • 由于所有子类型已知,无需 else 分支:
fun log(e: Error) 
   when (e) 
       is FileReadError -> println("FileReadError")
       is DatabaseError -> println("DatabaseError")
       is RuntimeError -> println("RuntimeError")
   

  • 一旦密封类的子类有所变更,IDE 里面的 when 表达式会立即提示,非常人性化:

‘when’ expression on sealed classes is recommended to be exhaustive, add ‘is NetworkResultError’ branch or ‘else’ branch instead

当然,在实际使用过程中,我们也可以实现层级更复杂的密封类:


与枚举的区别

看起来是不是跟枚举有点像?确实如此,甚至从某种程度上我们可以称密封类为加强版的枚举。
但是每种枚举只能有一个实例,但是密封类没有这个限制。

参考文档

以上是关于对比Java学Kotlin密封类的主要内容,如果未能解决你的问题,请参考以下文章

对比Java学Kotlin密封类

对比Java学Kotlin官方文档目录

对比Java学Kotlin嵌套类和内部类

对比Java学Kotlin嵌套类和内部类

对比Java学Kotlin嵌套类和内部类

对比Java学Kotlin类属性