You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中密封类与默认final类的核心差异是什么?

密封类与默认final类的核心差异

Kotlin里默认final类和密封类虽然都对类层级有约束,但两者的设计意图、开放范围和功能特性完全不同,核心差异可以从以下几点拆解:

1. 继承的开放程度完全不同

  • 默认final类是完全禁止继承:比如你示例中的Hi类,任何其他类都无法继承它,目的是确保类的行为不会被子类修改,保持封装的完整性。
  • 密封类是有限制地开放继承:它允许子类在特定范围内(同一个文件内,或者密封类的内部)被定义,但不允许在外部随意扩展。比如你的Fruit密封类,Apple和Mango只能定义在Fruit内部或同一个.kt文件中,外部无法新增Orange这类子类来扩展Fruit的层级。

2. 类型安全的穷尽性检查支持

密封类的子类是有限且明确可知的,这让Kotlin编译器能在when表达式中做穷尽性检查:

fun describeFruit(fruit: Fruit): String {
    return when(fruit) {
        is Fruit.Apple -> "这是苹果,名字:${fruit.x}"
        is Fruit.Mango -> "这是芒果,名字:${fruit.x}"
        // 这里不需要写else分支,编译器确认所有子类都已覆盖
    }
}

而默认final类不存在子类,自然没有这种场景;哪怕是手动开放的open类,因为子类可以无限扩展,编译器无法做穷尽性检查,必须写else分支。

3. 设计意图的本质区别

  • 默认final类的核心目标是封装与不可变性:通过禁止继承,避免子类重写父类方法导致的行为异常,保证类的稳定性和可预测性,适合那些不需要扩展的工具类、数据类等。
  • 密封类的核心目标是表示固定的类型集合:它是枚举的扩展——枚举只能是单例,而密封类的子类可以有自己的属性和多个实例,同时又能像枚举一样保证类型的有限性,适合用来表示状态(比如加载中、成功、失败)、事件类型等场景。

比如密封类可以实现带属性的多实例子类:

sealed class Fruit(val name: String) {
    class Apple(val weight: Double) : Fruit("Apple") // 可以创建多个不同重量的Apple实例
    class Mango(val ripeLevel: Int) : Fruit("Mango")
}

这是枚举和final类都做不到的。

内容的提问来源于stack exchange,提问作者vinayak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 18:46:10