Kotlin-Sealed与Open的使用

Open的使用

open 就像给 Kotlin 类 / 方法 "拆了锁"------ 默认情况下它们都是 "上锁" 的(不能被继承 / 重写),加了 open 才允许子类 "进门修改"。

打个生活比方:你买的新手机(普通类)默认系统是 "只读" 的,不能随便刷自定义系统(继承重写);而 open 就像给手机解了 BL 锁,现在你才能 root、刷第三方系统(子类继承并修改父类功能)。

具体用法:3 个核心场景
  • 修饰类 :允许这个类被其他类继承。例:open class Phone() → 子类 class XiaomiPhone : Phone()(能继承);如果不加 open,写 class Phone(),子类继承会直接报错。
  • 修饰方法 :允许子类重写(覆盖)这个方法的逻辑。例:父类 open fun call() = "基础通话",子类 override fun call() = "视频通话"(能重写);不加 open 的方法,子类不能写 override
  • 修饰属性 :允许子类重写属性的值或 getter/setter。例:父类 open val price = 1000,子类 override val price = 2000(能重写)。

简单说,Kotlin 用 open 明确 "哪些东西可以被改",避免像 Java 那样默认全开放、容易不小心改乱父类逻辑,是一种 "安全的开放开关"。

sealed(密封类)的使用

一、sealed(密封类)怎么用?一句话总结:

限定子类范围,让编译器知道 "所有可能的情况",避免漏写判断 ,最常用在 when 表达式里。

具体用法(3 步):
  1. 用 sealed 修饰父类 :父类可以是 class 或 interface(Kotlin 1.5 + 支持接口),通常用 sealed class
  2. 子类必须和父类在同一文件 / 同一密封类内部:不能在其他文件定义子类,彻底锁死继承范围。
  3. when 表达式不用写 else:因为编译器能枚举所有子类,不用担心漏情况。
例子(比普通类更安全):
kotlin 复制代码
// 1. 密封类(父类)
sealed class Result
// 2. 子类(必须在同一文件)
class Success(val data: String) : Result()
class Error(val msg: String) : Result()

// 3. when 使用(不用写 else,漏了会报错)
fun handleResult(result: Result) = when (result) {
    is Success -> println("成功:${result.data}") // 编译器知道有这个子类
    is Error -> println("失败:${result.msg}")   // 编译器知道有这个子类
    // 这里不用写 else!漏写任何子类会直接编译报错
}

二、底层原理:本质是 "编译期的语法糖"

底层没有特殊的 "密封类字节码",而是编译器帮我们做了两件事,实现 "子类范围锁定":

  1. 父类构造器私有化 :普通类默认有公开构造器,而 sealed 类的构造器会被编译器偷偷改成 private,阻止外部直接 new 父类,也阻止外部文件继承(因为子类必须调用父类构造器,private 构造器只能在同一文件访问)。
  2. 给子类加标记 + 帮 when 做检查 :编译器会给每个子类加隐藏标记,在 when 表达式里,会自动校验 "是否覆盖了所有带标记的子类",漏了就报错 ------ 本质是编译期的静态检查,不是运行时的限制。

三、为什么要用?对比普通类的优势

比如用普通类写上面的 Result:

kotlin 复制代码
// 普通父类
open class Result
class Success(val data: String) : Result()
class Error(val msg: String) : Result()

// when 必须写 else,否则编译器担心漏情况
fun handleResult(result: Result) = when (result) {
    is Success -> println("成功")
    is Error -> println("失败")
    else -> println("未知情况") // 必须写,哪怕永远走不到
}

如果后续加了个 Loading 子类,用普通类时 when 不会报错,可能漏掉处理;但用 sealed 类,编译器会强制你在 when 里加 is Loading 的判断,避免逻辑漏洞。

Kotlin中open和sealed的使用场景

简单说:需要灵活扩展时用 open,需要固定范围时用 sealed,两者是"开放"和"封闭"的两种极端场景选择。

1. 用 open 的场景:需要"后续能加新功能"

当你不确定未来会有多少子类,想留足扩展空间时用 open,核心是"允许新增"。

比如:

  • 定义"基础组件":如 open class Animal,后续能随时加 DogCatBird 等子类,不用改父类。
  • 实现"多态逻辑":如 open fun pay()(基础支付),子类能重写成 WechatPayAlipay,各自实现不同支付逻辑。
  • 框架/库设计:比如 Android 里的 open class Activity,允许开发者继承它写自己的 MainActivity,灵活定制页面。

2. 用 sealed 的场景:需要"明确所有可能情况"

当你能确定"子类就这么几个,不会再多了",且要避免漏处理时用 sealed,核心是"范围锁死"。

比如:

  • 定义"状态/结果":如网络请求的 sealed class Result,只可能是 SuccessErrorLoading,不会有其他情况,when 判断时能确保覆盖所有状态。
  • 处理"固定选项":如订单状态 sealed class OrderStatus,只有 Pending(待支付)、Paid(已支付)、Cancelled(已取消),后续不会新增,逻辑不会有漏洞。
  • 枚举的"增强版":比普通 enum 更灵活(能传参数,如 Success(val data: String)),同时保持"选项固定"的特性。
相关推荐
90后的晨仔2 小时前
Vue 插槽(Slots)全面解析与实战指南
前端·vue.js
golang学习记2 小时前
从0死磕全栈之Next.js API 路由实战:不用后端,前端也能写接口!
前端
用户2018792831672 小时前
SIGABRT+GL errors Native Crash 问题分析
android
MQliferecord2 小时前
前端性能优化实践经验总结
前端
2501_916013742 小时前
iOS 26 设备文件管理实战指南,文件访问、沙盒导出、系统变更与 uni-app 项目适配
android·ios·小程序·uni-app·cocoa·iphone·webview
RoyLin3 小时前
SurrealDB - 统一数据基础设施
前端·后端·typescript
程序员二黑3 小时前
告别硬编码!5个让Web自动化脚本更稳定的定位策略
面试·单元测试·测试
longlongago~~3 小时前
富文本编辑器Tinymce的使用、行内富文本编辑器工具栏自定义class、katex渲染数学公式
前端·javascript·vue.js
2501_915921433 小时前
前端用什么开发工具?常用前端开发工具推荐与不同阶段的选择指南
android·前端·ios·小程序·uni-app·iphone·webview