Kotlin data 关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的 data 关键字简化了创建主要用于存储数据的类。 它会自动生成有用的方法,例如 toString、equals 和 hashCode。 本教程通过实际示例深入探讨了 data 关键字。
基本定义
Kotlin 中的 data 关键字将一个类标记为数据类。 数据类旨在存储数据,并自动为标准方法提供实现。 它们非常适合创建具有最少样板代码的 POJO(普通旧 Java 对象)。
基本数据类
一个简单的数据类需要在类声明之前使用 data 关键字。 主构造函数必须至少有一个参数。 所有参数都将自动成为属性。
package com.zetcode
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("John Doe", 30)
println(person) // Output: Person(name=John Doe, age=30)
}
这里,我们定义了一个具有两个属性的 Person 数据类。 Kotlin 自动生成一个可读的 toString 方法。 输出以标准化格式显示属性名称及其值。
Equals 和 HashCode
数据类根据在主构造函数中声明的所有属性自动实现 equals 和 hashCode 方法。 这确保了正确的相等比较。
package com.zetcode
data class Product(val id: Int, val name: String, val price: Double)
fun main() {
val p1 = Product(1, "Laptop", 999.99)
val p2 = Product(1, "Laptop", 999.99)
println(p1 == p2) // Output: true
println(p1.hashCode() == p2.hashCode()) // Output: true
}
具有相同属性值的两个 Product 实例被视为相等。 hashCode 值也匹配,这使得它们适合在基于哈希的集合中使用,例如 HashSet 或 HashMap。
Copy 函数
数据类提供一个 copy 函数,该函数创建一个新实例,其中一些属性已更改。 这对于希望创建修改后的副本的不可变数据结构很有用。
package com.zetcode
data class Book(val title: String, val author: String, val year: Int)
fun main() {
val book1 = Book("Kotlin in Action", "Dmitry Jemerov", 2017)
val book2 = book1.copy(title = "Kotlin Cookbook", year = 2022)
println(book1) // Output: Book(title=Kotlin in Action, ...)
println(book2) // Output: Book(title=Kotlin Cookbook, ...)
}
copy 函数创建一个新的 Book 实例,该实例具有相同的作者,但标题和年份不同。 在新实例中保留了在 copy 中未指定的原始属性。
解构声明
数据类启用解构声明,允许您将一个对象拆包成多个变量。 这有效,因为数据类会自动提供 componentN 函数。
package com.zetcode
data class Point(val x: Int, val y: Int)
fun main() {
val point = Point(10, 20)
val (xCoord, yCoord) = point
println("X: $xCoord, Y: $yCoord") // Output: X: 10, Y: 20
}
Point 实例被解构为 xCoord 和 yCoord 变量。 变量的顺序与主构造函数声明中的属性顺序匹配。
默认和命名参数
数据类在其构造函数中支持默认值和命名参数。 这在创建实例的同时提供了灵活性,同时保持了代码的整洁。
package com.zetcode
data class User(
val username: String,
val email: String = "",
val active: Boolean = true
)
fun main() {
val user1 = User("johndoe")
val user2 = User("janedoe", "jane@example.com", false)
val user3 = User(username = "admin", active = true)
println(user1) // Output: User(username=johndoe, email=, active=true)
println(user2) // Output: User(username=janedoe, email=jane@example.com, active=false)
println(user3) // Output: User(username=admin, email=, active=true)
}
User 数据类演示了 email 和 active 属性的默认值。 我们可以使用不同的参数组合创建实例,使用位置参数或命名参数。
数据类的限制
数据类有一些限制。 它们不能是抽象的、开放的、密封的或内部的。 它们必须具有一个主构造函数,该构造函数至少具有一个参数,并且所有参数都必须标记为 val 或 var。
package com.zetcode
// This won't compile - data class can't be abstract
// abstract data class Shape(val sides: Int)
// This won't compile - data class needs at least one parameter
// data class Empty()
fun main() {
data class Temp(val value: Int) // Local data classes are allowed
val temp = Temp(42)
println(temp) // Output: Temp(value=42)
}
注释的示例显示了无效的数据类声明。 但是,数据类可以在函数中本地声明,如 Temp 类所示。 这对于临时数据结构很有用。
带有附加成员的数据类
虽然数据类主要处理数据,但它们可以包含其他成员,例如方法或辅助构造函数。 但是,仅主构造函数属性用于生成的 方法。
package com.zetcode
data class Employee(
val id: Int,
val name: String
) {
var department: String = "Unassigned"
fun promote() {
department = "Management"
}
}
fun main() {
val emp = Employee(101, "Alice")
emp.department = "Engineering"
emp.promote()
println(emp) // Output: Employee(id=101, name=Alice)
println("Department: ${emp.department}") // Output: Department: Management
}
Employee 数据类包括一个附加属性和方法。 请注意, toString 输出仅包括主构造函数属性。 必须单独访问其他成员。
数据类的最佳实践
- 用于数据持有者: 数据类非常适合主要目的是保存数据的类。
- 保持不可变性: 尽可能使用
val属性使数据类不可变。 - 利用 copy: 使用
copy方法创建不可变数据类的修改后的实例。 - 考虑解构: 当您需要一次访问多个属性时,请使用解构声明。
- 避免复杂的逻辑: 保持数据类专注于数据存储,而不是复杂的业务逻辑。
来源
本教程深入介绍了 Kotlin 的 data 关键字,展示了如何有效创建和使用数据类。 我们探讨了自动方法生成、复制、解构和限制。 数据类减少了样板代码,同时为以数据为中心的类提供了强大的功能。
作者
列出 所有 Kotlin 教程。