密封类和接口表示受限制的类层次结构,提供对继承的更多控制。密封类的所有直接子类在编译时都是已知的。在定义密封类的模块和包之外不能出现其他子类。例如,第三方客户端不能在其代码中扩展您的密封类。因此,密封类的每个实例都有一个在编译该类时已知的有限集合中的类型。

参考官网:https://kotlinlang.org/docs/sealed-classes.html

如果您像我一样,第一次阅读时可能无法理解这一点,特别是在没有实际代码示例的情况下。

1、密封类的特性

  • 密封类是抽象的,可以有抽象成员。

  • 密封类不能直接实例化。

  • 密封类不能有公共构造函数(默认情况下构造函数是私有的)。

  • 密封类可以有子类,但它们必须在同一个文件中,或者嵌套在密封类声明中。

  • 密封类的子类可以在密封类文件之外拥有子类。

2、Kotlin中的密封类:基本示例

下面是一个的密封类的基本示例:

sealed class Animal

上面代码的重要部分是“密封”修饰符。正如在密封类规则中提到的,密封类可以有子类,但它们必须都在同一个文件中,或者嵌套在密封类声明中。但是,密封类的子类不必在同一个文件中。

// 子类嵌套在密封类
sealed class Animal {class Dog() : Animal()class Cat() : Animal()
}sealed class Animal
//子类不嵌套在密封类中,但必须在同一个文件类中
class Dog() : Animal()
class Cat() : Animal()// Animal.kt
sealed class Animal() {class Dog() : Animal()class Cat() : Animal()open class UnKnownAnimal() : Animal()
}
// OtherAnimal.kt
class Duck : Animal()//编译失败
class cow : Animal.UnKnownAnimal()//编译成功

使用密封类的主要好处是在when表达式中使用它们时发挥作用。如果可以验证语句是否涵盖所有情况,则不需要向语句添加else子句。但是,只有当您使用when作为表达式(使用结果)而不是作为语句时,这才有效。

//Animal.kt
sealed class Animal() {class Dog() : Animal()class Cat() : Animal()
}//MainAnimal.kt
//编译失败,由于没有复关全部子类结果
fun getAnimalName(type:Animal):String{return when (type){is Animal.Cat -> "Cat"}
}

上面这段代码失败了,因为我们必须实现所有类型。抛出的错误是:

'when' expression must be exhaustive, add necessary 'is Dog' branch or 'else' branch instead

这意味着我们必须在when表达式中包含所有类型的Animal。

fun getAnimalName(type:Animal):String{return when (type){is Animal.Cat -> "Cat"is Animal.Dog -> "Dog"}
}

3、Kotlin中的密封类:应用形式

a、带继承的密封类

密封类可以有子类,这允许您创建更复杂的类层次结构。下面是一个密封类层次结构的例子,它表示一个成功的结果和各种类型的错误:

sealed class Result<out T> {data class Success<out T>(val data: T) : Result<T>()sealed class Error : Result<Nothing>() {data class NetworkError(val code: Int) : Error()object Timeout : Error()object Unknown : Error()}
}

b、具有泛型类型的密封类

还可以将泛型类型与密封类一起使用,以创建更灵活和可重用的代码。下面是一个用泛型表示UI状态的密封类层次结构的例子:

sealed class UIState<out T> {data class Success<out T>(val data: T) : UIState<T>()data class Error(val message: String) : UIState<Nothing>()object Loading : UIState<Nothing>()
}

c、带扩展函数的密封类

与枚举类似,也可以使用扩展函数向密封类添加功能。下面是一个扩展函数的例子,它将一个Result密封的类实例映射到UIState:

fun <T> Result<T>.toUIState(): UIState<T> {return when (this) {is Result.Success -> UIState.Success(data)is Result.Error.NetworkError -> UIState.Error("Network error: $code")is Result.Error.Timeout -> UIState.Error("Request timed out")is Result.Error.Unknown -> UIState.Error("Unknown error")}
}

4、思考

在面向对象编程中,有时候我们想要隐藏一些类的实现细节,只暴露其子类。

通常情况可以将基础类的构造函数声明为 protected 或 private 来实现。这样,只有子类才能调用基础类的构造函数来创建对象,外部类无法创建基础类的对象,从而隐藏了基础类的实现细节。

以下是一个示例,演示如何隐藏基础类只暴露其子类:

open class Animal protected constructor(val name: String) {// 隐藏构造函数,只能被子类调用open fun makeSound() {println("This animal makes a sound.")}
}class Dog(name: String) : Animal(name) {override fun makeSound() {println("Woof!")}
}class Cat(name: String) : Animal(name) {override fun makeSound() {println("Meow!")}
}

在上面的代码中,我们定义了一个名为 Animal 的基础类,并将其构造函数声明为 protected,这意味着只有 Animal 的子类才能访问该构造函数。我们还定义了两个子类 DogCat,它们继承自 Animal 类。注意到,它们都没有定义自己的构造函数,因此它们将使用从 Animal 类继承的构造函数来创建对象。

通过这种方式,我们可以在不暴露 Animal 类的实现细节的情况下,使用 DogCat 类来创建动物对象。例如:

val dog = Dog("Fido")
val cat = Cat("Whiskers")

在上面的代码中,我们使用 DogCat 类来创建 dogcat 对象,它们都是 Animal 类的子类,但是我们无法直接创建 Animal 对象。

需要注意的是,使用 protected 修饰构造函数的类可以被继承,这意味着在同一包内部可以创建子类;如果有这样的需求,不想要再让外部自定义子类只使用现有定义的子类,这种情况就无法满足了,这里我们就想到了密封类sealed

我们已经知道,在 Kotlin 中,可以使用 sealed 关键字定义一个密封类(sealed class),从而避免外部直接实例化该类。

密封类是一个抽象类,用于限制类的继承层级,只能在其内部定义子类。外部无法继承密封类,也无法直接实例化密封类,只能通过其子类来实例化。

以下是一个使用 sealed 关键字定义密封类的例子:

sealed class Animal {abstract fun makeSound()
}class Dog : Animal() {override fun makeSound() {println("汪汪汪")}
}class Cat : Animal() {override fun makeSound() {println("喵喵喵")}
}

在上面的例子中,Animal 是一个密封类,它的子类只能在 Animal 内部定义,而外部无法继承或直接实例化 Animal 类。我们定义了 DogCat 两个子类,用于表示狗和猫。

通过使用 sealed 关键字,我们可以限制类的继承层级,确保所有的子类都在密封类内部定义,从而避免了外部直接实例化该类的情况,也避免了外部去自定义扩展子类。

理解Kotlin密封类Sealed相关推荐

  1. kotlin密封类_Kotlin密封级

    kotlin密封类 In this tutorial, we'll be looking into Kotlin Sealed Class. What are they? What's their u ...

  2. kotlin_基础_密封类(sealed)

    原文链接:https://blog.csdn.net/weixin_41953808/article/details/112499887 Kotlin密封类:sealed 密封类:用来定义受限的类继承 ...

  3. 【JDK 17】密封类 sealed、permits、non-sealed

    密封类(Sealed Classes) 作用 限制类的继承实现, 只允许指定的子类去继承 关键字 sealed .permits.non-sealed 使用 使用时,密封类的父子类 必须  是同包 写 ...

  4. Kotlin 密封类代替枚举类

    密封类代替枚举类 在Kotlin中由于密封类的特性,所以可以完全取代枚举类 应为object是final类,所以不能继承普通类,但是密封类是abstract,所以可以继承 示例中使用了中缀符号infi ...

  5. 理解 Kotlin 中的属性(property)

    这篇文章是一时兴起想写的,因为我发现我对Kotlin的属性理解一直有误 Java 中的属性是什么(property) 首先我们要搞清楚在 Java 中属性是什么,在 Java 中类的属性不是指一个字段 ...

  6. C# 密封类sealed

    1.密封类定义 如果我们不希望自己编写的类被继承:如果有的类已经没有再被继承的必要,这时,我们可以使用sealed修饰符在类中进行声明,以达到该类不能派生其它类的目的,该类就被称为密封类. 2.密封类 ...

  7. pdf 深入理解kotlin协程_Kotlin协程实现原理:挂起与恢复

    今天我们来聊聊Kotlin的协程Coroutine. 如果你还没有接触过协程,推荐你先阅读这篇入门级文章What? 你还不知道Kotlin Coroutine? 如果你已经接触过协程,但对协程的原理存 ...

  8. pdf 深入理解kotlin协程_协程初探

    Hello,各位朋友,小笨鸟我回来了! 近期学习了Kotlin协程相关的知识,感觉这块技术在项目中的可应用性很大,对项目的开发效率和维护成本有较大的提升.于是就考虑深入研究下相关概念和使用方式,并引入 ...

  9. 【深入理解Kotlin协程】Google的工程师们是这样理解Flow的?

    Question:why there is a Flow in kotlin? 问这个问题就好比在问为什么那里会有一座山存在,嗯,这貌似是一个哲学问题.当然,对于kotlin中的Flow的理解可能不会 ...

最新文章

  1. 让你更好使用Vista的设置技巧
  2. 无线抄表免费透传云服务器,两个WIFI模块USR-WIFI232-B2连接有人云实现远程一对一透传...
  3. 阿里一年,聊聊我成长了什么,入职阿里的职业生涯感悟
  4. 微服务架构案例(03):数据库选型简介,业务数据规划设计
  5. Hadoop集群(第2期)_机器信息分布表
  6. android瀑布流效果(仿蘑菇街)
  7. 软考网络工程师--知识产权与标准化
  8. jquery的pagination插件实现无刷新的分页
  9. HashTable 源码解析 jdk1.8
  10. 【TSP】基于matlab粒子群算法求解旅行商问题【含Matlab源码 445期】
  11. 信息安全的 CIA 三要素
  12. linux 批量convert,使用convert来批量处理图片
  13. 一个Java基础练习
  14. POJ 3713 Transferring Sylla​ 题解 《挑战程序设计竞赛》
  15. linux系统外接硬盘_linux下,如何挂载一块硬盘?
  16. 苹果手机外放没声音怎么回事
  17. 【手机端测试的关注点】Android 和 IOS 两大主流系统测试点
  18. NFS导致df -h卡主解决
  19. 记录一下手把手教您做电商网站
  20. ios6.0 siri语音识别

热门文章

  1. 模式识别的一些基本概念
  2. 前端:下拉选项框及文本框的实现
  3. 合并代码,解决冲突,最简单方法!
  4. astah_激活步骤
  5. 解决树莓派4B无线鼠标迟滞/延迟的问题
  6. html2canvas生成长图片时导致背景图渲染不全问题
  7. flux 中的 buffer 的原理
  8. Topk实现(C++)
  9. 松下幸之助语录-2011
  10. 微信会员注册开发【带源码】:网页授权,得到code后在当前页面获取openid,js+php实现跨域请求