sealed class(密封类) 的主要作用是约束类的继承结构,它比enum class更加灵活,但又比普通的类继承体系更严谨。

简单来说,sealed class就像一个“有限的”类族。你不能在定义sealed class的文件之外继承它,这意味着编译器知道它所有的子类,这带来了两大优势:

  1. 更强的类型安全: 编译器可以强制你处理所有可能的子类。
  2. 更智能的when表达式:when表达式中,如果你列出了所有可能的子类,编译器会要求你不需要再写else分支。

sealed class vs. enum class

虽然它们都能用来表示一组有限的类型,但它们的设计目的和适用场景不同。

特性enum class(枚举类)sealed class(密封类)
实例数量每个枚举项只有一个实例(单例)。每个子类都可以有多个实例,并且可以包含自己的状态和数据。
携带数据枚举项可以有属性,但通常数据是固定的。子类可以拥有不同的属性和状态,并且可以携带任意数据。
灵活性固定的一组常量,每个常量都是一个对象。灵活的继承结构,子类可以是data classobject或普通类。
主要用途表示一组不变的、固定的常量集合,如星期几、方向等。表示一个有限的、可变的数据结构集合,例如网络请求的不同状态(成功、失败、加载中)。

使用场景和示例

用一个网络请求的例子来对比,你会更容易理解。

如果用enum class

你可能这样定义网络请求的状态:

enum class Result {
    SUCCESS,
    FAILURE
}

这种方式的问题是,你无法在FAILURE状态中携带错误信息,也无法在SUCCESS状态中携带成功的数据。

如果用sealed class

你可以定义一个sealed class来表示网络请求的所有可能状态,并且每个状态都可以携带不同的数据。

sealed class Result {
    // 加载中,不需要额外数据
    object Loading : Result() 
 
    // 成功,携带成功的数据
    data class Success(val data: String) : Result() 
 
    // 失败,携带错误信息
    data class Failure(val error: Exception) : Result() 
}

使用时,when表达式会变得非常简洁和安全:

fun handleResult(result: Result) {
    when (result) {
        is Result.Loading -> println("加载中...")
        is Result.Success -> println("数据加载成功: ${result.data}")
        is Result.Failure -> println("加载失败: ${result.error.message}")
    }
}

由于sealed class的所有子类都已经被编译器知道,你不需要写else分支,因为它能保证你已经处理了所有可能的情况。这能有效防止你漏掉某个状态,让代码更健壮。


总而言之,sealed class不仅仅是enum class的替代品,它更像是一种加强版的、带有层级结构的数据枚举。它在表示有限状态机、处理网络请求结果或 UI 状态等场景下,能够提供比enum class更强大的类型安全和灵活性。

更新: 2025-08-07 09:56:13
原文: https://www.yuque.com/dongpozhouzi-mshe3/zhm85g/ok9rh2k326isgmz3


相关笔记