Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

数据类

Kotlin 减少了重复性的编码工作

class 机制为您执行了大量的工作。然而,创建主要用于保存数据的类仍然需要大量重复的代码。当您需要一个基本上是数据持有者的类时,data 类简化了您的代码并执行常见的任务。

在 Kotlin 中,data 类简化了主要用于保存数据的类的代码,减少了重复性的编码工作。

您可以使用 data 关键字定义一个 data 类,告诉 Kotlin 生成额外的功能。每个构造函数参数前面必须加上 varval

// DataClasses/Simple.kt
package dataclasses
import atomictest.eq

data class Simple(
  val arg1: String,
  var arg2: Int
)

fun main() {
  val s1 = Simple("Hi", 29)
  val s2 = Simple("Hi", 29)
  s1 eq "Simple(arg1=Hi, arg2=29)"
  s1 eq s2
}

这个例子展示了 data 类的两个特点:

  1. 通过 s1 产生的 String 与我们通常看到的不同;它包含对象所持有的参数名称和值的信息。data 类以一种漂亮、可读的格式显示对象,而无需额外的代码。
  2. 如果您创建了两个包含相同数据(属性的相等值)的相同 data 类的实例,您可能希望这两个实例也相等。对于普通类,要实现这种行为,您必须定义一个特殊的 equals() 函数来比较实例。在 data 类中,这个函数会自动生成;它会比较所有指定为构造函数参数的属性的值。

下面是一个普通类 Person 和一个 dataContact 的例子:

// DataClasses/DataClasses.kt
package dataclasses
import atomictest.*

class Person(val name: String)

data class Contact(
  val name: String,
  val number: String
)

fun main() {
  // 这两个看起来是相同的,但实际上不是:
  Person("Cleo") neq Person("Cleo")
  // data 类定义了合理的相等性:
  Contact("Miffy", "1-234-567890") eq
  Contact("Miffy", "1-234-567890")
}
/* 输出结果:
dataclasses.Person@54bedef2
Contact(name=Miffy, number=1-234-567890)
*/

因为 Person 类是没有使用 data 关键字定义的,所以包含相同 name 的两个实例并不相等。幸运的是,将 Contact 定义为 data 类会得到合理的结果。

请注意 data 类的显示格式与 Person 的区别,Person 只显示默认的对象信息。

对于每个 data 类,还生成了一个非常有用的函数 copy(),它创建一个包含当前对象数据的新对象。但是,它也允许您在此过程中更改选定的值:

// DataClasses/CopyDataClass.kt
package dataclasses
import atomictest.eq

data class DetailedContact(
  val name: String,
  val surname: String,
  val number: String,
  val address: String


)

fun main() {
  val contact = DetailedContact(
    "Miffy",
    "Miller",
    "1-234-567890",
    "1600 Amphitheatre Parkway")
  val newContact = contact.copy(
    number = "098-765-4321",
    address = "Brandschenkestrasse 110")
  newContact eq DetailedContact(
    "Miffy",
    "Miller",
    "098-765-4321",
    "Brandschenkestrasse 110")
}

copy() 函数的参数名称与构造函数参数相同。所有参数都有默认值,等于当前值,因此您只需要提供要替换的参数的值。

HashMap 和 HashSet

创建一个 data 类还会生成适当的 哈希函数,以便对象可以用作 HashMapHashSet 中的键:

// DataClasses/HashCode.kt
package dataclasses
import atomictest.eq

data class Key(val name: String, val id: Int)

fun main() {
  val korvo: Key = Key("Korvo", 19)
  korvo.hashCode() eq -2041757108
  val map = HashMap<Key, String>()
  map[korvo] = "Alien"
  map[korvo] eq "Alien"
  val set = HashSet<Key>()
  set.add(korvo)
  set.contains(korvo) eq true
}

hashCode()equals() 结合使用,快速查找 HashMapHashSet 中的 Key。手动创建正确的 hashCode() 是棘手且容易出错的,因此让 data 类为您完成这项工作非常有益。有关 equals()hashCode() 的更多详细信息,请参阅运算符重载

在 www.AtomicKotlin.com 上可以找到练习和解答。