数据类

Data classes in Kotlin are primarily used to hold data. For each data class, the compiler automatically generates additional member functions that allow you to print an instance to readable output, compare instances, copy instances, and more. Data classes are marked with data:

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

编译器自动从主构造函数中声明的所有属性导出以下成员:

  • .equals()/.hashCode() 对。
  • .toString() 格式是 "User(name=John, age=42)"
  • .componentN() 函数 按声明顺序对应于所有属性。
  • .copy() 函数(见下文)

为了确保生成的代码的一致性以及有意义的行为,数据类必须满足以下要求:

  • 主构造函数必须至少有一个参数。
  • 主构造函数的所有参数必须标记为 valvar
  • 数据类不能是抽象、开放、密封或者内部的。

此外,数据类成员的生成遵循关于成员继承的这些规则:

  • 如果在数据类体中有显式实现 .equals().hashCode() 或者 .toString(),或者这些函数在父类中有 final 实现,那么不会生成这些函数,而会使用现有函数。
  • 如果超类型具有 open.componentN() 函数并且返回兼容的类型, 那么会为数据类生成相应的函数,并覆盖超类的实现。如果超类型的这些函数由于签名不兼容或者是 final 而导致无法覆盖,那么会报错。
  • 不允许为 .componentN() 以及 .copy() 函数提供显式实现。

数据类可以扩展其他类(示例请参见密封类)。

在 JVM 中,如果生成的类需要含有一个无参的构造函数,那么属性必须指定默认值。(参见构造函数):

data class User(val name: String = "", val age: Int = 0)

在类体中声明的属性

请注意,对于那些自动生成的函数,编译器只使用在主构造函数内部定义的属性。 如需在生成的实现中排除一个属性,请将其声明在类体中:

data class Person(val name: String) {
    var age: Int = 0
}

In the example below, only the name property is used by default inside the .toString(), .equals(), .hashCode(), and .copy() implementations, and there is only one component function, .component1(). The age property is declared inside the class body and is excluded. Therefore, two Person objects with the same name but different age values are considered equal since .equals() only evaluates properties from the primary constructor:

data class Person(val name: String) {
    var age: Int = 0
}
fun main() {
//sampleStart
    val person1 = Person("John")
    val person2 = Person("John")
    person1.age = 10
    person2.age = 20

    println("person1 == person2: ${person1 == person2}")
    // person1 == person2: true

    println("person1 with age ${person1.age}: ${person1}")
    // person1 with age 10: Person(name=John)

    println("person2 with age ${person2.age}: ${person2}")
    // person2 with age 20: Person(name=John)
//sampleEnd
}

复制

Use the .copy() function to copy an object, allowing you to alter some of its properties while keeping the rest unchanged. The implementation of this function for the User class above would be as follows:

fun copy(name: String = this.name, age: Int = this.age) = User(name, age)

然后可以这样写:

val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)

数据类与解构声明

为数据类生成的 component 函数 使它们可在解构声明中使用:

val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") 
// Jane, 35 years of age

标准数据类

标准库提供了 PairTriple 类。尽管在很多情况下具名数据类是更好的设计选择, 因为它们通过为属性提供有意义的名称使代码更具可读性。