详解Kotlin的各种类(使用场景导向)

目录

  1. [数据类 data class](#数据类 data class)
  2. [枚举类 enum class](#枚举类 enum class)
  3. [密封类 / 密封接口 sealed class / sealed interface](#密封类 / 密封接口 sealed class / sealed interface)
  4. [对象声明 object](#对象声明 object)
  5. [伴生对象 companion object](#伴生对象 companion object)
  6. [接口 interface & 函数式接口 fun interface](#接口 interface & 函数式接口 fun interface)
  7. [内部类 / 嵌套类 inner class / 嵌套类](#内部类 / 嵌套类 inner class / 嵌套类)
  8. [值类 @JvmInline value class](#值类 @JvmInline value class)
  9. 选型速查表

数据类 data class ------ 纯数据载体 & UI 状态首选

适用场景
  • 网络/数据库返回模型UserDtoArticleDtoOrderDto
  • Compose / MVVM / MVI 中的 UI 状态 UiState
  • 需要频繁做:
    • 比较(==
    • 日志打印(toString
    • 拷贝修改部分字段(copy
    • 解构(val (id, name) = user
示例:网络返回 + UI 状态
kotlin 复制代码
// 网络数据模型
data class UserDto(
    val id: Long,
    val name: String,
    val email: String
)

// UI 状态(配合 MVVM / MVI)
data class UserListUiState(
    val loading: Boolean = false,
    val users: List<UserDto> = emptyList(),
    val error: String? = null
)

// ViewModel 内使用:只改一部分字段
var uiState by mutableStateOf(UserListUiState())

fun showLoading() {
    uiState = uiState.copy(loading = true, error = null)
}

fun showUsers(list: List<UserDto>) {
    uiState = uiState.copy(loading = false, users = list, error = null)
}

fun showError(msg: String) {
    uiState = uiState.copy(loading = false, error = msg)
}
关键点
  • 一切"数据结构、状态对象 "优先考虑 data class
  • 在 Compose 里:所有 UiState 几乎都应是 data class ,配合 copy 非常自然。

枚举类 enum class ------ 离散、小而固定的状态

适用场景
  • 状态是有限且固定 的:
    • 用户角色:ADMIN / USER / GUEST
    • 加载状态:LOADING / SUCCESS / ERROR
    • 主题模式:LIGHT / DARK / SYSTEM
  • 不同状态不需要带额外字段
    (需要带不同字段时优先 sealed class
示例:加载状态
kotlin 复制代码
enum class LoadStatus {
    IDLE,
    LOADING,
    SUCCESS,
    ERROR
}

data class PageUiState(
    val status: LoadStatus = LoadStatus.IDLE,
    val data: List<String> = emptyList(),
    val errorMsg: String? = null
)

fun render(uiState: PageUiState) {
    when (uiState.status) {
        LoadStatus.IDLE    -> showIdle()
        LoadStatus.LOADING -> showLoading()
        LoadStatus.SUCCESS -> showContent(uiState.data)
        LoadStatus.ERROR   -> showError(uiState.errorMsg)
    }
}
关键点
  • 只是"标签不同、结构一样/没字段"的状态 → 用 enum class
  • 搭配 when 使用,可读性高,Java 开发者非常熟悉。

密封类 / 密封接口 sealed class / sealed interface ------ 一组"有差异的状态"

适用场景
  • 一组状态,每个状态字段不一样
    • Loading / Success(data) / Error(msg)
  • 希望 when 分支必须穷尽所有状态(编译器帮你防漏分支)
  • 更"强类型"的状态管理,常见于 MVI、复杂状态机
示例:通用网络结果
kotlin 复制代码
sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val message: String, val cause: Throwable? = null) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

// ViewModel 暴露给 UI
val userResult: StateFlow<Result<UserDto>> = _userResult

// Compose 渲染
@Composable
fun UserScreen(viewModel: UserViewModel) {
    val result by viewModel.userResult.collectAsState()

    when (result) {
        is Result.Loading -> CircularProgressIndicator()
        is Result.Success -> UserView((result as Result.Success<UserDto>).data)
        is Result.Error   -> ErrorView((result as Result.Error).message)
    }
}
示例:登录状态
kotlin 复制代码
sealed class LoginState {
    object Idle : LoginState()
    object Loading : LoginState()
    data class Success(val user: UserDto) : LoginState()
    data class Error(val message: String) : LoginState()
}

fun render(state: LoginState) = when (state) {
    LoginState.Idle         -> showIdle()
    LoginState.Loading      -> showLoading()
    is LoginState.Success   -> showUser(state.user)
    is LoginState.Error     -> showError(state.message)
}
关键点
  • 差异大(字段不同) → sealed ;差异小,只是名字不一样 → enum
  • Compose / MVI 里非常常见:sealed class UiStatesealed class Intent 等。

对象声明 object ------ 单例 & 工具 & 全局配置

适用场景
  • 全局唯一实例:LoggerNetworkConfigServiceLocator
  • 无状态工具类:DateUtilsPasswordValidator
  • 替代 Java 的 static 单例 / 工具类
示例:网络配置单例
kotlin 复制代码
object NetworkConfig {
    const val TIMEOUT_MS = 30_000

    var baseUrl: String = "https://api.example.com"

    fun printConfig() {
        println("baseUrl = $baseUrl, timeout = $TIMEOUT_MS")
    }
}

// 使用
val url = NetworkConfig.baseUrl
NetworkConfig.printConfig()
示例:工具类
kotlin 复制代码
object PasswordValidator {
    fun isValid(pwd: String): Boolean {
        return pwd.length >= 8 && pwd.any { it.isDigit() }
    }
}

if (PasswordValidator.isValid(input)) {
    // ...
}
关键点
  • 天然线程安全的单例,比 Java 手写单例简单、可靠。
  • 不要在 object 中持有 Activity / Context 等短生命周期对象,防止内存泄漏。

伴生对象 companion object ------ Kotlin 的 "static" 区

适用场景
  • 类相关的常量:默认值、Key、Tag 等
  • 工厂方法:MyClass.fromJson(...)of(...)
  • 与 Java 互操作时,模拟 static 方法/字段
示例:常量 + 工厂方法
kotlin 复制代码
data class User(
    val id: Long,
    val name: String
) {
    companion object {
        const val DEFAULT_ID = -1L

        fun fromName(name: String): User {
            return User(DEFAULT_ID, name.trim())
        }
    }
}

// 使用
val u1 = User.fromName("Tom")
val id = User.DEFAULT_ID
ViewModel 中的使用
kotlin 复制代码
class LoginViewModel(...) : ViewModel() {
    companion object {
        const val MAX_RETRY = 3
    }
}
关键点
  • 类似 Java 的 staticUser.fromName()User.DEFAULT_ID
  • 一般情况不用特意加 @JvmStatic,除非给 Java 调用时有特殊需求。

接口 interface & 函数式接口 fun interface ------ 回调 & 策略

普通接口 interface

适用场景:

  • 抽象行为:RepositoryService 等,用实现类替换
  • 解耦 ViewModel 与具体实现,例如注入 AuthServiceUserRepository
kotlin 复制代码
interface AuthService {
    suspend fun login(username: String, password: String): Result<UserDto>
}

class AuthServiceImpl(...) : AuthService { ... }

class LoginViewModel(
    private val authService: AuthService
) : ViewModel() { ... }
函数式接口 fun interface(单方法接口)

适用场景:

  • 回调 / 策略,尤其需要和 Java 互操作时
  • 希望 既是接口,又能用 Lambda 写得很简洁
kotlin 复制代码
fun interface ErrorHandler {
    fun onError(message: String)
}

fun doSomething(onError: ErrorHandler) {
    // ...
}

// 使用,直接 Lambda
doSomething { msg -> println("Error: $msg") }

对比:

  • 在纯 Kotlin 代码里,很多时候可以直接用函数类型 (String) -> Unit 代替。
  • 若需要更强语义或 Java 互操作,使用 fun interface

内部类 / 嵌套类 inner class / 嵌套类 ------ 尽量少用,只在确实需要时

区别示例
kotlin 复制代码
class Outer {
    private val outerValue = 10

    // 嵌套类:不持有 Outer 实例 → 类似 Java static class
    class Nested {
        fun hello() = println("I'm nested")
    }

    // 内部类:持有 Outer 实例 → 类似 Java 非静态内部类
    inner class Inner {
        fun print() = println(outerValue)  // 可以访问 outerValue
    }
}
适用场景
  • 嵌套类(默认):仅做逻辑分组的辅助类,不需要访问外部类实例。
  • inner class
    • 确实需要访问外部类实例,并接受它的生命周期。
    • 在 Android 中要非常谨慎,容易引起内存泄漏。

建议:

  • 有 Java 背景的老习惯是随手写内部类,但在 Kotlin / Android:
    • 默认用"嵌套类"(不写 inner)
    • 只有当确实需要访问外部实例时,才用 inner

值类 @JvmInline value class ------ 更安全的"标量包装"

适用场景
  • 同为 Long / String,但语义完全不同,希望类型区分 避免传错:
    • UserId vs ProductId
    • Money vs Distance
  • 希望在性能敏感场景中尽量不创建额外对象(编译器做 inline 优化)
示例:区分不同 ID
kotlin 复制代码
@JvmInline
value class UserId(val value: Long)

@JvmInline
value class ProductId(val value: Long)

fun loadUser(userId: UserId) { /* ... */ }
fun loadProduct(productId: ProductId) { /* ... */ }

// 使用
loadUser(UserId(1L))
loadProduct(ProductId(1L))  // 不能混用,编译期类型安全
关键点
  • 内部只有一个属性。
  • 编译器会尽量在 JVM 层"拆箱",避免多余对象,但不是绝对。
  • 更偏向类型安全 / 可读性提升的工具,适合领域模型设计。

选型速查表

根据"想表达什么",快速选用合适的 Kotlin 类形态:

需求 / 场景 推荐用法
一坨字段组成的"数据结构"或 UI 状态 data class
少数、固定、不带额外数据的状态 enum class
一组差异较大的状态,每个状态字段不同 sealed class / sealed interface
全局单例 / 配置 / 工具 object
类级别常量 / 工厂方法 / 静态工具函数 companion object
回调 / 策略接口,且需要 Java 互操作 fun interface(或函数类型)
同是 Long/String 但语义不同(ID/金额等) @JvmInline value class
需要访问外部类实例的内部类 inner class(谨慎使用)
相关推荐
小屁猪qAq2 小时前
C++预处理过程详解
开发语言·c++·预处理·编译
从此不归路2 小时前
Qt5 进阶【8】数据库操作与数据访问层实战:用 Qt 搭一套好用的持久化“地基”
开发语言·c++·qt
浒畔居2 小时前
C++中的状态模式实战
开发语言·c++·算法
android_cai_niao2 小时前
kotlin中好用的集合扩展函数
kotlin·集合
naruto_lnq2 小时前
C++中的状态模式
开发语言·c++·算法
Whisper_Sy10 小时前
Flutter for OpenHarmony移动数据使用监管助手App实战 - 网络状态实现
android·java·开发语言·javascript·网络·flutter·php
Bony-11 小时前
Go语言垃圾回收机制详解与图解
开发语言·后端·golang
hmywillstronger11 小时前
【Rhino】【Python】 查询指定字段并cloud标注
开发语言·python
新缸中之脑11 小时前
Weave.js:开源实时白板库
开发语言·javascript·开源