1、数据类的定义
我们常常创建一些类,其主要目的是保存数据。在这样的类中,一些标准的功能性和实用性函数自动从数据中生成。在Kotlin中,这样的类被称为数据类,并被标记为数据。例如
data class User(val name: String,val age: Int)
编译器会从主构造函数中的所有参数自动生成以下成员:
equals()/hashCode() 对
toString() "User(name=John, age=42)"的形式
componentN() 函数 对应于所有属性的声明顺序
copy() 函数
为确保生成代码的一致性和意义性,数据类必须满足以下要求:
- 主构造函数至少有一个参数
- 主构造函数的所有参数 必须 标记为
val
或者var
- 数据类不能用 abstract、open、sealed 或者 inner修饰
- 在1.1 前,数据类只能实现接口;1.1后,可以继承其它类
另外,关于成员继承,成员的生成需要遵循这些规则:
- 如果数据类的类体中
equals()
,hashCode()
ortoString()
已明确实现或者在父类中 有final
实现。那么这些函数不会被生成,并且使用现有的实现; - 如果超类型中有
open
和返回兼容类型的componentN()
函数,则为数据类生成相应的函数并覆盖超类型的函数。如果因为 不兼容的签名 或者 变成final
,超类型中的这些函数不能被覆盖,则会报错。 - 不允许为
componentN()
和copy()
提供显示的实现
在 JVM 中,如果生成的类需要含有一个无参的构造函数,则所有的属性必须指定默认值。
data class User(val name: String = "", val age: Int = 0)
2、Copying
很多情况下,我们需要复制一个对象来改变它的一些属性,担保持其它部分不变。copy()
函数就是为此而生成。对于上文的 User 类,其实现会类似下面这样:
fun copy(name: String = this.name, val age: this.age) = User(name,age)
我们可以这样用:
val jack = User(name = "Jack", age = 1) or val jack = User("Jack", 1)
val olderJack = jack.copy(age = 2)
println(olderjack.toString()) // User(name=Jack, age=2)
3、数据类和解构声明
为数据类生成的组件函数 可用于解构声明中:
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // prints "Jane, 35 years of age"
4、标准的数据类
标准库提供了 Pair
和Triple
。尽管如此,大多数情况下,命名数据类是个更好的选择,因为他们通过为属性提供有意义的名称使得代码更易读。