0
点赞
收藏
分享

微信扫一扫

19:kotlin 类和对象 -- 密封类和接口(Sealed classes and interfaces )

勇敢乌龟 2023-12-04 阅读 51
kotlin

使用sealed关键字声明一个密封类或者接口

sealed interface Error

sealed class IOError(): Error

密封类和接口能够很好的控制继承,在密封类和接口定义的模块和包外无法被继承

在编译期我们就已知了所有的密封类和接口的实现类。在某种意义上,密封类类似于枚举类:枚举类型的值集也是受限制的,但枚举常量只存在为单个实例,而密封类的子类可以有多个实例,每个实例都有自己的状态。

举例来说,有个公共方法模块,定义了一个顶级错误密封类Error,只要是模块中捕获了Error的子类异常,就证明是当前模块抛出的错误,可以根据子类类型分别作出不同的处理。如果不是密封类,其他模块也继承了Error类,因为不是在当前模块定义的,被当前模块捕获后没有相应的处理方式,可能导致运行异常。因为密封类的特性,所有子类型都是已知的,不会被其他模块继承,避免了上述未知异常

package com.example

sealed interface Error 
class CustomError() : Error 
package io.example

import com.example.Error

class CustomError(): Error // 报错 -- Inheritor of sealed class or interface declared in package io.example but it must be in package com.example where base class is declared

密封类本身是抽象类,不能直接实例化,可以有抽象成员

密封类的构造函数可以是protected或者private,默认为protected

sealed class IOError {
    constructor() { /*...*/ } // 默认protected
    private constructor(description: String): this() { /*...*/ } // private
    // public constructor(code: Int): this() {} // 报错 -- Error: public and internal are not allowed
}

直接子类位置(Location of direct subclasses)

  • 直接子类必须在相同的包内声明。
  • 子类可以是顶层类,也可以嵌套在任意数量的其他命名类、命名接口或命名对象内。
  • 子类可以具有任何可见性,只要它们符合kotlin的正常继承规则。
  • 密封类的子类必须具有正确的限定名称。
  • 子类不能是局部的,也不能是匿名对象

这些限制不适用于间接子类。如果密封类的直接子类没有标记为密封类,那么它可以根据其修饰符允许的任何方式进行扩展

sealed interface Error // has implementations only in same package and module

sealed class IOError(): Error // extended only in same package and module
open class CustomError(): Error // can be extended wherever it's visible

多平台继承

在以后章节中讲解

密封类和When表达式

使用密封类的主要好处是在when表达式中使用它们时发挥作用。如果可以验证语句涵盖所有情况,则不需要在语句中添加else子句

fun log(e: Error) = when(e) {
    is FileReadError -> { println("Error while reading file ${e.file}") }
    is DatabaseError -> { println("Error while reading from database ${e.source}") }
    is RuntimeError ->  { println("Runtime error") }
    // the `else` clause is not required because all the cases are covered
}
举报

相关推荐

0 条评论