Kotlin 密封类 #

一、密封类概述 #

密封类(sealed class)用于表示受限的类层次结构,所有子类必须在与密封类相同的文件中定义。

二、定义密封类 #

2.1 基本语法 #

kotlin
sealed class Result

class Success(val data: String) : Result()
class Error(val message: String) : Result()
object Loading : Result()

2.2 使用场景 #

kotlin
fun handle(result: Result): String {
    return when (result) {
        is Success -> "Success: ${result.data}"
        is Error -> "Error: ${result.message}"
        Loading -> "Loading..."
    }
}

2.3 完整示例 #

kotlin
sealed class UIState {
    object Loading : UIState()
    data class Success(val data: String) : UIState()
    data class Error(val message: String) : UIState()
}

class ViewModel {
    private var state: UIState = UIState.Loading
    
    fun setState(newState: UIState) {
        state = newState
    }
    
    fun render(): String {
        return when (state) {
            is UIState.Loading -> "Loading..."
            is UIState.Success -> "Data: ${state.data}"
            is UIState.Error -> "Error: ${state.message}"
        }
    }
}

三、密封类子类 #

3.1 数据类子类 #

kotlin
sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val code: Int, val message: String) : Result()
}

3.2 对象子类 #

kotlin
sealed class Permission {
    object Granted : Permission()
    object Denied : Permission()
}

3.3 普通类子类 #

kotlin
sealed class Shape {
    class Circle(val radius: Double) : Shape()
    class Rectangle(val width: Double, val height: Double) : Shape()
}

3.4 混合类型 #

kotlin
sealed class Expr {
    data class Const(val number: Double) : Expr()
    data class Sum(val e1: Expr, val e2: Expr) : Expr()
    object NotANumber : Expr()
}

四、when 表达式 #

4.1 完整覆盖 #

kotlin
sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
}

fun handle(result: Result): String = when (result) {
    is Result.Success -> "Success: ${result.data}"
    is Result.Error -> "Error: ${result.message}"
    // 不需要 else 分支,编译器会检查是否覆盖所有情况
}

4.2 新增子类时编译器提示 #

kotlin
sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
    object Loading : Result()  // 新增子类
}

fun handle(result: Result): String = when (result) {
    is Result.Success -> "Success: ${result.data}"
    is Result.Error -> "Error: ${result.message}"
    // 编译器会提示缺少 Loading 分支
}

五、密封接口 #

5.1 定义密封接口 #

kotlin
sealed interface Action

object Start : Action
object Stop : Action
data class Execute(val command: String) : Action

5.2 实现密封接口 #

kotlin
sealed interface Shape {
    val area: Double
}

data class Circle(val radius: Double) : Shape {
    override val area: Double = Math.PI * radius * radius
}

data class Rectangle(val width: Double, val height: Double) : Shape {
    override val area: Double = width * height
}

六、实战示例 #

6.1 网络请求状态 #

kotlin
sealed class NetworkState<out T> {
    object Idle : NetworkState<Nothing>()
    object Loading : NetworkState<Nothing>()
    data class Success<T>(val data: T) : NetworkState<T>()
    data class Error(val exception: Throwable) : NetworkState<Nothing>()
}

fun <T> handleState(state: NetworkState<T>) {
    when (state) {
        is NetworkState.Idle -> println("Idle")
        is NetworkState.Loading -> println("Loading...")
        is NetworkState.Success -> println("Success: ${state.data}")
        is NetworkState.Error -> println("Error: ${state.exception.message}")
    }
}

6.2 表达式计算器 #

kotlin
sealed class Expr {
    data class Const(val value: Double) : Expr()
    data class Sum(val left: Expr, val right: Expr) : Expr()
    data class Mul(val left: Expr, val right: Expr) : Expr()
    data class Div(val left: Expr, val right: Expr) : Expr()
}

fun eval(expr: Expr): Double = when (expr) {
    is Expr.Const -> expr.value
    is Expr.Sum -> eval(expr.left) + eval(expr.right)
    is Expr.Mul -> eval(expr.left) * eval(expr.right)
    is Expr.Div -> {
        val right = eval(expr.right)
        if (right != 0.0) eval(expr.left) / right else Double.NaN
    }
}

val expr = Expr.Sum(
    Expr.Const(1.0),
    Expr.Mul(Expr.Const(2.0), Expr.Const(3.0))
)
println(eval(expr))  // 7.0

6.3 支付方式 #

kotlin
sealed class PaymentMethod {
    data class CreditCard(
        val number: String,
        val expiryDate: String
    ) : PaymentMethod()
    
    data class PayPal(val email: String) : PaymentMethod()
    
    data class BankTransfer(
        val accountNumber: String,
        val routingNumber: String
    ) : PaymentMethod()
}

fun processPayment(method: PaymentMethod, amount: Double): String {
    return when (method) {
        is PaymentMethod.CreditCard -> 
            "Processing $amount via Credit Card ending in ${method.number.takeLast(4)}"
        is PaymentMethod.PayPal -> 
            "Processing $amount via PayPal (${method.email})"
        is PaymentMethod.BankTransfer -> 
            "Processing $amount via Bank Transfer"
    }
}

6.4 导航事件 #

kotlin
sealed class NavigationEvent {
    data class ToDetail(val id: Int) : NavigationEvent()
    data class ToProfile(val userId: String) : NavigationEvent()
    object Back : NavigationEvent()
    data class ToUrl(val url: String) : NavigationEvent()
}

fun navigate(event: NavigationEvent) {
    when (event) {
        is NavigationEvent.ToDetail -> 
            println("Navigate to detail: ${event.id}")
        is NavigationEvent.ToProfile -> 
            println("Navigate to profile: ${event.userId}")
        is NavigationEvent.Back -> 
            println("Go back")
        is NavigationEvent.ToUrl -> 
            println("Open URL: ${event.url}")
    }
}

七、密封类 vs 枚举类 #

7.1 枚举类 #

kotlin
enum class State {
    LOADING, SUCCESS, ERROR
}

7.2 密封类 #

kotlin
sealed class State {
    object Loading : State()
    data class Success(val data: String) : State()
    data class Error(val message: String) : State()
}

7.3 区别 #

特性 枚举类 密封类
实例数量 固定一个 可以有多个
状态 单例 可以携带数据
继承 不能继承 可以继承
接口 可以实现 可以实现

7.4 选择建议 #

kotlin
// 使用枚举:固定状态,无数据
enum class Direction { NORTH, SOUTH, EAST, WEST }

// 使用密封类:有数据的状态
sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val code: Int) : Result()
}

八、最佳实践 #

8.1 命名规范 #

kotlin
// 推荐:状态后缀
sealed class UIState { }
sealed class NetworkResult { }

// 推荐:事件后缀
sealed class NavigationEvent { }

8.2 使用 data class 携带数据 #

kotlin
sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
}

8.3 使用 object 表示无数据状态 #

kotlin
sealed class State {
    object Loading : State()
    object Idle : State()
    data class Data(val value: String) : State()
}

九、总结 #

密封类要点:

特性 说明
受限继承 子类必须在同一文件
when 完整性 编译器检查覆盖
携带数据 子类可以携带数据
状态管理 适合表示有限状态

下一步,让我们学习 枚举类

最后更新:2026-03-27