Kotlin 密封类 (Sealed Class)

密封类用于限制继承关系 ,即一个类的所有子类都必须在同一个文件 中定义。它本质上是枚举的升级版------枚举用于固定的一组对象 ,密封类用于固定的一组类型

核心特点

  1. 子类受限:所有子类在编译时已知,只能出现在同一文件中;
  2. 可以有多个实例:相比枚举(每个常量只有一个实例),密封类的子类可以有多个对象;
  3. 支持状态携带:不同子类可携带不同类型的数据;

基本语法

kotlin 复制代码
sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
    object Loading : Result()
}

主要使用场景

1. 状态机表示(最常见)

kotlin 复制代码
sealed class NetworkState {
    object Idle
    object Loading
    data class Success(val data: String)
    data class Error(val code: Int)
}

2. UI 事件/视图状态

kotlin 复制代码
sealed class LoginEvent {
    data class OnEmailChange(val email: String)
    data class OnPasswordChange(val pwd: String)
    object OnSubmitClick
}

与 when 表达式的完美配合

kotlin 复制代码
fun handleState(state: Result) {
    when (state) {
        is Result.Success -> println(state.data)
        is Result.Error -> println(state.message)
        Result.Loading -> println("加载中")
        // 无需 else 分支,编译器知道所有可能情况
    }
}

与其他类型的对比

特性 密封类 枚举 普通抽象类
子类型数量 固定,编译时已知 固定 无限制
单例/多实例 两者都支持 仅单例 两者都支持
携带状态 ✅ 不同子类可不同 ❌ 所有常量相同结构
模式匹配 ✅ 完整检查 ⚠️ 有限

实例:加载用户信息

kotlin 复制代码
// 1. 定义密封类表示加载状态
sealed class LoadState<out T> {
    object Idle : LoadState<Nothing>()
    object Loading : LoadState<Nothing>()
    data class Success<T>(val data: T) : LoadState<T>()
    data class Error(val message: String) : LoadState<Nothing>()
}

// 2. 模拟数据仓库
class UserRepository {
    fun fetchUser(userId: String): LoadState<User> {
        return when {
            userId.isEmpty() -> LoadState.Error("用户ID不能为空")
            userId == "404" -> LoadState.Error("用户不存在")
            else -> LoadState.Success(User(userId, "张三", 25))
        }
    }
}

data class User(val id: String, val name: String, val age: Int)

// 3. UI 层处理状态
class UserViewModel {
    private val repo = UserRepository()
    
    fun loadUser(userId: String) {
        var state: LoadState<User> = LoadState.Loading
        println("状态: 加载中...")
        
        state = repo.fetchUser(userId)
        
        // 4. 使用 when 表达式处理所有情况(无需 else)
        when (state) {
            is LoadState.Idle -> println("状态: 空闲")
            is LoadState.Loading -> println("状态: 加载中")
            is LoadState.Success -> {
                println("状态: 成功")
                println("用户: ${state.data.name}, ${state.data.age}岁")
            }
            is LoadState.Error -> println("状态: 失败 - ${state.message}")
        }
    }
}

// 5. 测试
fun main() {
    val vm = UserViewModel()
    
    println("=== 测试1: 正常加载 ===")
    vm.loadUser("123")
    
    println("\n=== 测试2: 空ID ===")
    vm.loadUser("")
    
    println("\n=== 测试3: 不存在的用户 ===")
    vm.loadUser("404")
}

注意事项

  • 密封类本身是抽象的,不能直接实例化
  • Kotlin 1.5+ 允许子类定义在不同文件的同一编译单元内,但通常还是放同一文件更清晰
  • 密封类可以继承接口,也可以被继承(仅限子类)

简单总结:当想表达 "某个值只能是几种类型之一,且每种类型可以携带不同数据" 时,就用密封类。

相关推荐
唐青枫11 小时前
Kotlin let 详解:空安全、链式转换与实战示例
kotlin
alexhilton19 小时前
车载系统中的可扩展UI:从UI嵌入到系统窗口编排
android·kotlin·android jetpack
日光明媚1 天前
一步生成视频!One-Forcing:DMD + 零成本 GAN,训练 200 步超越多步 SOTA
android·开发语言·kotlin
plainGeekDev1 天前
Android运行时面试题:ART和JVM的区别都搞不清,别写精通了
jvm·面试·kotlin
Refrain_zc3 天前
Android Kotlin + MVVM:基于 LiveData 的段落列表音频播放与 AB 复读实现
kotlin
赏金术士3 天前
企业级 Jetpack Compose 项目(入门版)最佳结构
android·kotlin·compose
我是唐青枫3 天前
Kotlin Lambda 表达式详解:从基础语法到实战封装
开发语言·kotlin
Kapaseker3 天前
Kotlin 的扩展没有你看上去的那么简单
android·kotlin
黄林晴3 天前
告别 KMP 选型地狱!klibs.io 上线,全平台库一键筛选太省心
android·kotlin
吕氏春秋i3 天前
android kotlin Compose 蓝牙库推荐
android·gitee·kotlin