目录
- [数据类
data class](#数据类 data class) - [枚举类
enum class](#枚举类 enum class) - [密封类 / 密封接口
sealed class / sealed interface](#密封类 / 密封接口 sealed class / sealed interface) - [对象声明
object](#对象声明 object) - [伴生对象
companion object](#伴生对象 companion object) - [接口
interface& 函数式接口fun interface](#接口 interface & 函数式接口 fun interface) - [内部类 / 嵌套类
inner class/ 嵌套类](#内部类 / 嵌套类 inner class / 嵌套类) - [值类
@JvmInline value class](#值类 @JvmInline value class) - 选型速查表
数据类 data class ------ 纯数据载体 & UI 状态首选
适用场景
- 网络/数据库返回模型 :
UserDto、ArticleDto、OrderDto等 - 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 UiState、sealed class Intent等。
对象声明 object ------ 单例 & 工具 & 全局配置
适用场景
- 全局唯一实例:
Logger、NetworkConfig、ServiceLocator - 无状态工具类:
DateUtils、PasswordValidator - 替代 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 的
static:User.fromName()、User.DEFAULT_ID。 - 一般情况不用特意加
@JvmStatic,除非给 Java 调用时有特殊需求。
接口 interface & 函数式接口 fun interface ------ 回调 & 策略
普通接口 interface
适用场景:
- 抽象行为:
Repository、Service等,用实现类替换 - 解耦 ViewModel 与具体实现,例如注入
AuthService、UserRepository
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,但语义完全不同,希望类型区分 避免传错:UserIdvsProductIdMoneyvsDistance
- 希望在性能敏感场景中尽量不创建额外对象(编译器做 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(谨慎使用) |