Kotlin 数据类与密封类

Kotlin 数据类与密封类(2025年中文讲解)

Kotlin 的数据类(Data Class)密封类(Sealed Class)是两种强大的类类型,专为特定场景设计,简化代码并增强类型安全。数据类用于存储数据,自动生成常用方法(如 toStringequals),而密封类用于限制类层次,适合建模有限状态或类型,广泛应用于 Android(Jetpack Compose)、后端(Spring Boot)和 Kotlin Multiplatform(KMP)项目。2025年,Kotlin 2.0(K2 编译器)优化了数据类和密封类的性能,尤其在 KMP 和 Compose 中应用广泛。本教程详细讲解两者的语法、用法和实践,基于官方文档、CSDN 和知乎,适合初学者和开发者。建议用 Kotlin Playground(https://play.kotlinlang.org/)练习。


一、数据类(Data Class)

1. 数据类概览(必知)
  • 定义:用 data class 关键字,专为存储数据设计,自动生成 toStringequalshashCodecopy 方法。
  • 特点
  • 简洁:无需手动实现 getter/setter 或 toString
  • 不可继承:数据类默认 final,不可用 open 继承。
  • 空安全:支持可空类型(?)。
  • 用途:JSON 解析、数据库实体、UI 数据模型。
  • 2025年趋势:数据类在 Jetpack Compose 和 KMP 中占主导,用于传递 UI 状态或跨平台数据。
2. 数据类语法与用法
  • 基本语法:主构造函数至少一个参数,参数需为 valvar
  data class User(val id: Int, val name: String)
  fun main() {
      val user = User(1, "Alice")
      println(user) // 输出:User(id=1, name=Alice)
      println(user.name) // 输出:Alice
      val user2 = user.copy(name = "Bob") // 复制并修改
      println(user2) // 输出:User(id=1, name=Bob)
      println(user == user2) // 输出:false(比较内容)
  }
  • 自动生成方法
  • toString():格式化输出对象。
  • equals()hashCode():基于主构造函数属性比较。
  • copy():创建对象副本,可修改部分属性。
  • 解构声明:val (id, name) = user
  • 解构声明
  fun main() {
      val user = User(1, "Alice")
      val (id, name) = user // 解构
      println("ID: $id, Name: $name") // 输出:ID: 1, Name: Alice
  }
  • 空安全
  data class Product(val id: Int?, val name: String?)
  fun main() {
      val product = Product(null, null)
      println(product) // 输出:Product(id=null, name=null)
      val safeName = product.name ?: "Unknown"
      println(safeName) // 输出:Unknown
  }
  • 添加方法
  data class Student(val id: Int, val name: String) {
      fun greet() = println("Hello, $name!")
  }
  fun main() {
      val student = Student(1, "Bob")
      student.greet() // 输出:Hello, Bob!
  }
3. 注意事项
  • 限制
  • 主构造函数至少一个参数。
  • 参数必须是 valvar(非临时变量)。
  • 不能用 open(不可继承)。
  • 最佳实践
  • 用于简单数据模型,避免复杂逻辑。
  • 优先 val 参数,确保不可变性。
  • 结合空安全(??:)处理可空数据。
  • 性能:Kotlin 2.0 优化 copyequals 性能,适合高频使用。

二、密封类(Sealed Class)

1. 密封类概览(必知)
  • 定义:用 sealed class 关键字,限制类的继承层次,所有子类必须定义在同一文件或模块内。
  • 特点
  • 类型安全:适合建模有限状态(如 API 响应、UI 状态)。
  • 与 when 结合when 表达式可穷尽所有子类,无需 else
  • 可继承:子类可以是普通类、数据类或其他密封类。
  • 用途:状态机、枚举增强、KMP 跨平台逻辑。
  • 2025年趋势:密封类在 Jetpack Compose(UI 状态管理)和 KMP(平台特定逻辑)中广泛使用。
2. 密封类语法与用法
  • 基本语法
  sealed class Result
  data class Success(val data: String) : Result()
  data class Error(val message: String) : Result()
  object Loading : Result()
  fun processResult(result: Result) = when (result) {
      is Success -> println("Success: ${result.data}")
      is Error -> println("Error: ${result.message}")
      is Loading -> println("Loading...")
  }
  fun main() {
      processResult(Success("Data loaded")) // 输出:Success: Data loaded
      processResult(Error("Failed")) // 输出:Error: Failed
      processResult(Loading) // 输出:Loading...
  }
  • 说明
  • 子类(SuccessErrorLoading)必须在同一文件或模块。
  • when 表达式自动穷尽所有子类,无需 else
  • 嵌套密封类
  sealed class Operation {
      sealed class Math : Operation() {
          data class Add(val a: Int, val b: Int) : Math()
          data class Subtract(val a: Int, val b: Int) : Math()
      }
      object Reset : Operation()
  }
  fun execute(op: Operation) = when (op) {
      is Operation.Math.Add -> println("Result: ${op.a + op.b}")
      is Operation.Math.Subtract -> println("Result: ${op.a - op.b}")
      is Operation.Reset -> println("Reset")
  }
  fun main() {
      execute(Operation.Math.Add(5, 3)) // 输出:Result: 8
      execute(Operation.Reset) // 输出:Reset
  }
  • 空安全
  sealed class Response
  data class Success(val data: String?) : Response()
  data class Error(val error: String?) : Response()
  fun handleResponse(response: Response) = when (response) {
      is Success -> println("Data: ${response.data ?: "No data"}")
      is Error -> println("Error: ${response.error ?: "Unknown error"}")
  }
  fun main() {
      handleResponse(Success(null)) // 输出:Data: No data
      handleResponse(Error("Timeout")) // 输出:Error: Timeout
  }
3. 注意事项
  • 限制
  • 子类必须在同一文件或模块(Kotlin 1.5+ 放宽为模块内)。
  • 密封类不能实例化(抽象类)。
  • 最佳实践
  • 用于有限状态(如 API 响应、UI 状态)。
  • 结合 when 确保类型安全。
  • 子类用 data classobject 简化实现。
  • 性能:Kotlin 2.0 优化 when 匹配密封类的字节码,效率提升。

三、实践示例(综合应用)

  1. 命令行示例(API 响应处理)
sealed class ApiResponse
data class Success(val data: String) : ApiResponse()
data class Error(val message: String) : ApiResponse()
object Loading : ApiResponse()

fun processResponse(response: ApiResponse) = when (response) {
    is Success -> println("Data: ${response.data}")
    is Error -> println("Error: ${response.message}")
    is Loading -> println("Loading...")
}

fun main() {
    val responses = listOf(
        Success("User data"),
        Error("Network failure"),
        Loading
    )
    responses.forEach { processResponse(it) }
}


输出

   Data: User data
   Error: Network failure
   Loading...
  1. Android 示例(UI 状态管理)
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

sealed class UiState
data class Loaded(val user: User) : UiState()
data class Error(val message: String) : UiState()
object Loading : UiState()
data class User(val id: Int, val name: String)

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val textView: TextView = findViewById(R.id.textView)
        val button: Button = findViewById(R.id.button)
        var state: UiState = Loading
        button.setOnClickListener {
            state = when (state) {
                is Loading -> Loaded(User(1, "Alice"))
                is Loaded -> Error("Failed to refresh")
                is Error -> Loading
            }
            textView.text = when (state) {
                is Loading -> "Loading..."
                is Loaded -> "User: ${(state as Loaded).user.name}"
                is Error -> "Error: ${(state as Error).message}"
            }
        }
    }
}


布局(res/layout/activity_main.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Press button" />
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Change State" />
</LinearLayout>


功能:点击按钮循环切换 UI 状态(Loading → Loaded → Error),显示对应文本。


四、注意事项与最佳实践

  1. 数据类
  • 用途:适合简单数据模型(如 JSON、数据库实体)。
  • 限制:不可继承,参数需 val/var
  • 空安全:优先用 ?: 处理可空属性。
  • 优化:Kotlin 2.0 减少 copy 开销,适合高频操作。
  1. 密封类
  • 用途:建模有限状态(如 API 响应、UI 状态)。
  • 与 when 结合:确保穷尽所有子类,增强类型安全。
  • 子类选择:用 data class 存储数据,object 表示单例状态。
  1. 2025年趋势
  • Jetpack Compose:数据类用于 UI 状态,密封类管理状态切换。
  • KMP:密封类用 expect/actual 实现跨平台逻辑:
    kotlin expect sealed class PlatformResponse
  • AI 辅助:IntelliJ 的 Codeium 插件可生成数据类和密封类代码。

五、学习建议

  • 练习:用 Kotlin Playground 实践数据类(复制/解构)和密封类(状态处理)。
  • 资源
  • 官方文档:https://kotlinlang.org/docs/data-classes.html、https://kotlinlang.org/docs/sealed-classes.html
  • B站:尚硅谷 Kotlin 教程(免费,包含数据类和密封类)。
  • CSDN:搜索“Kotlin 数据类 密封类”。
  • 时间:2-3 天掌握两者,1 周熟悉 Android/KMP 结合。
  • 实践:开发小型 App(如用户列表、状态切换)。

六、总结

Kotlin 数据类密封类是现代开发利器:

  • 数据类必知自动生成方法(toStringcopy),必会定义、解构和空安全处理,适合数据模型。
  • 密封类必知类型安全和 when 穷尽,必会定义子类和状态处理,适合有限状态建模。
    2025年,Kotlin 2.0 提升性能,数据类和密封类在 Android(Compose)和 KMP 中广泛使用,相比 Java 更简洁、安全。

如果需要具体场景代码(如 Compose 状态管理或 KMP 示例)或有问题,告诉我,我可以提供更详细解答!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注