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)),同时保持"选项固定"的特性。
相关推荐
二宝1521 分钟前
黑马商城day10-Redis面试篇
数据库·redis·面试
Lisonseekpan1 分钟前
HTTP请求方法全面解析:从基础到面试实战
java·后端·网络协议·http·面试
吉星9527ABC2 分钟前
表示离散量的echarts图型示例
前端·arcgis·echarts·离散量web展示
悠哉清闲2 分钟前
SoundPool
android
光影少年4 分钟前
web3学习路线
前端·学习·前端框架·web3
克喵的水银蛇4 分钟前
Flutter 状态管理:Provider 入门到实战(替代 setState)
前端·javascript·flutter
鹏多多5 分钟前
flutter-使用url_launcher打开链接/应用/短信/邮件和评分跳转等
android·前端·flutter
刻刻帝的海角6 分钟前
响应式数据可视化 Dashboard
开发语言·前端·javascript
小飞侠在吗7 分钟前
vue3 中的 ref 和 reactive
前端·javascript·vue.js