请阐述 Kotlin 中 sealed class 的基本概念及其典型应用场景,并说明它相较于普通抽象类的独特之处。
考察说明
考察对 Kotlin 密封类的理解及其在实际设计中的应用能力。
回答思路
- 【回答框架 1】密封类是一种受限的类层次结构,使用 sealed 关键字修饰,其所有直接子类必须声明在同一个文件(Kotlin 1.5 前)或同一个模块(Kotlin 1.5+)内。它本身是抽象类,但构造函数默认私有,子类必须嵌套或位于同一文件,用于表示受限的、已知的子类型集合。
- 【回答框架 2】主要适用于状态管理、UI 事件处理、网络请求结果封装等场景,例如使用 sealed class 表示加载状态(Loading、Success、Error),可以确保 when 表达式覆盖所有情况,免去 else 分支。
- 【回答框架 3】与普通抽象类的区别在于:密封类明确限制了子类型的范围,编译器在 when 中可穷举检查,提升安全性;普通抽象类允许任意处继承,层次不受限制。
- 【回答框架 4】定义时 sealed class Result { data class Success(val data: T) : Result(); data class Error(val message: String) : Result() },使用时 when (result) { is Success -> ...; is Error -> ... },无需 else。
- 【回答框架 5】在 Kotlin 1.5+ 中,密封类的直接子类可以放在同一模块的不同文件中(但必须同包),增强了灵活性,但必须保证子类在同一编译单元内。
- 【关键点 1】密封类定义受限的类层次,所有直接子类在编译期已知。
- 【关键点 2】在 when 表达式中可穷举所有子类型,无需 else 分支,增强类型安全。
- 【关键点 3】经典场景包括状态机、网络请求包装、UI 状态管理等。
- 【关键点 4】相比普通抽象类,密封类限制了继承范围,便于维护和扩展。
- 【易错点 1】误以为密封类可以跨模块继承,实际受限于模块或文件。
- 【易错点 2】忘记在 when 中处理所有子类,导致编译错误(若未 else 分支)。
- 【易错点 3】将大而全的继承体系全部用密封类,导致文件膨胀,不如使用接口适当抽象。