当前位置: 首页 > backend >正文

Kotlin密封类

基本语法

要声明一个密封类(sealed class)或密封接口(sealed interface),我们只需要在类或接口前加上 sealed 修饰符:

sealed class CustomError 
sealed interface CustomErrors

解释代码:
密封类和密封接口的区别仅在于类与接口之间的差异,因此我们将继续以密封类为例进行说明。

一个密封类是抽象的,因此它不能被实例化。下面的代码会导致错误:

fun main() {// 密封类型不能实例化val customError = CustomError()
}

解释代码:
但是,当然,你可以扩展它。

就像普通类一样,密封类也可以声明构造函数,但密封类中的构造函数必须是私有的或受保护的:

sealed class CustomError {constructor(type: String) {} // 受保护的(默认)private constructor(type: String, code: Int) {} // 私有的public constructor() {} // 公共构造函数会导致错误
}

解释代码:
你还可以像普通类一样使用主构造函数:

// 主构造函数 
sealed class CustomError(type: String) 

密封类与枚举类的对比

理解密封类的一种很好的方法是将它与枚举类进行对比。基本上,密封类像枚举类,但它更灵活。以下是对比的例子:

enum class Staff(numberOfLessons: Int) {TEACHER(2), MANAGER("Manager is managing")
}

解释代码:
这是枚举类的例子,但枚举类中不能有不同类型的构造参数(例如整数和字符串)。然而,使用密封类时是可以的:

sealed class Staff {class Teacher(val numberOfLessons: Int) : Staff()class Manager(val Responsibility: String) : Staff()object Worker : Staff()
}

解释代码:
枚举常量只有一种类型,而密封类则提供了更多的实例和更大的灵活性。我们可以得出结论:枚举类用于表示一组固定的值,而密封类用于表示给定类的固定子类集合。

枚举类不能继承类或接口,而密封类则可以。例如:

open class Person {fun whoAmI(name: String): String {return "I am $name"}
}sealed class Staff : Person() {class Teacher(val numberOfLessons: Int) : Staff()class Manager(val Responsibility: String) : Staff()object Worker : Staff()
}fun main() {val worker = Staff.Workerprintln(worker.whoAmI("Worker"))
}

解释代码:
我们声明了一个简单的 Person 类,并定义了一个方法,然后扩展了密封类 Staff,这赋予了我们继承的能力。在 main 方法中,我们调用了 Person 类的方法。这样一来,我们就能继承 Person 类中的功能了。

另一方面,如果我们尝试使用枚举类来做相同的事情,会导致错误:

enum class Staff : Person() {//...//
}

密封类与 when 表达式

密封类通常与 when 表达式一起使用,因为每个类都被视为一个案例。以下是一个例子:

sealed class Staff {class Teacher(val numberOfLessons: Int) : Staff()class Manager(val Responsibility: String) : Staff()object Worker : Staff()
}fun listTheTasks(staff: Staff) = when (staff) {is Staff.Teacher -> println("The teacher has ${staff.numberOfLessons} lessons today")is Staff.Manager -> println("The manager is doing ${staff.Responsibility} today")Staff.Worker -> println("Worker is fixing the projector for profs in CS, all respect to him.")
}

解释代码:
我们声明了一个密封类 Staff,其中包含两个类和一个对象。一个对象在没有状态的情况下更为合适。然后我们创建了一个函数 listTheTasks。请注意,在类的情况下,需要使用 is,而在对象的情况下不需要。由于我们处理了所有的案例,因此没有 else 分支。

让我们运行这个函数:

fun main() {val teacher = Staff.Teacher(3)val worker = Staff.WorkerlistTheTasks(teacher)listTheTasks(worker)
}// 输出:
// The teacher has 3 lessons today
// Worker is fixing the projector for profs in CS, all respect to him.

解释代码:
如你所见,when 表达式可以非常方便地处理密封类的每个子类。

直接子类的位置

最后,重要的一点是,密封类和接口的直接子类必须声明在同一个包中。另一方面,这一点对间接子类没有要求。你可能会问,什么是直接子类和间接子类。让我们通过一个简单的例子来澄清:

open class B : A() // B 是 A 的直接子类
open class C : B() // C 是 A 的间接子类,B 的直接子类

解释代码:
如果父类与子类之间没有其他类,那么它就是直接子类。

官方文档中提到:“密封类的所有直接子类在编译时都是已知的。没有其他子类可以出现在模块/包之外。”

结论

在本节中,我们学习了密封类,正如名称所示,“sealed” 限制了类层次结构,在我们需要表示一组固定的子类时非常有用。

我们还发现,密封类像枚举类,但提供了更多的灵活性。我们还学习了如何与 when 表达式一起使用,并讨论了密封类的类层次结构的限制。

http://www.xdnf.cn/news/15607.html

相关文章:

  • 独家|理想汽车放弃华为PBC模式,回归OKR理想汽车
  • 常用API
  • 输尿管下段积水预测与手术决策支持技术方案
  • 现在遇到一个问题 要使用jmeter进行压测 jmeter中存在jar包 我们还要使用linux进行发压,这个jar包怎么设计使用
  • iOS App 电池消耗管理与优化 提升用户体验的完整指南
  • Unity VR多人手术模拟恢复2:客户端移动同步问题分析与解决方案
  • 华为P30/pro (ELE-AL00) 鸿蒙4.2降级 EMUI 9
  • npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1
  • C++性能优化与现代工程实践:打造高效可靠的软件系统
  • 部署-k8s和docker、jenkins的区别和联系
  • 深入理解 SemaphoreSlim 在.NET Core API 开发中的应用
  • Spring Boot整合阿里云OSS:企业级文件存储最佳实践
  • 贪心算法思想草稿
  • Spring AI之Prompt开发
  • Perspective:一款开源的交互式分析和数据可视化组件
  • 找不到或无法加载主类 org.gradle.wrapper.GradleWrapperMain
  • Maven详细解
  • 网络基础11 上公网--Internet接入技术
  • Python eval函数详解 - 用法、风险与安全替代方案
  • NLP——迁移学习
  • SQLite的可视化界面软件的安装
  • 【后端】.NET Core API框架搭建(8) --配置使用RabbitMQ
  • Kotlin属性重写
  • C++ AVL树实现详解:平衡二叉搜索树的原理与代码实现
  • 深度学习之神经网络(二)
  • cell2location复现
  • Clip微调系列:《CLIP-Adapter: Better Vision-Language Models with FeatureAdapters》
  • 深度学习中的注意力机制:原理、应用与实践
  • STM32-RTC内部时钟
  • 力扣 hot100 Day46