5.8.2 数据类
3 分钟阅读
5.8.2 数据类
Kotlin 中的数据类主要用于保存数据。对于每个数据类,编译器都会自动生成额外的成员函数,让你能以可读的形式打印实例、比较实例、复制实例等。数据类用 data 标记:
| |
编译器会根据主构造函数中声明的所有属性自动派生以下成员:
equals()/hashCode()组合。- 形如
"User(name=John, age=42)"的toString()。 - 与属性声明顺序相对应的
componentN()函数。 copy()函数。
为确保生成代码的一致性和有意义的行为,数据类必须满足以下要求:
- 主构造函数必须至少有一个参数。
- 所有主构造函数参数都必须标记为
val或var。 - 数据类不能是 abstract、open、sealed 或 inner。
此外,数据类成员的生成在成员的继承方面遵循以下规则:
- 如果数据类主体中已有
equals()、hashCode()或toString()的显式实现,或者超类中有它们的final实现,那么这些函数不会被生成,而是使用已有的实现。 - 如果某个超类型有
open且返回兼容类型的componentN()函数,则会为数据类生成相应的函数并重写超类型的那些函数。如果由于签名不兼容或因为是 final 而无法重写超类型的函数,则会报错。 - 不允许为
componentN()和copy()函数提供显式实现。
数据类可以继承其他类(示例见密封类)。
注意: 在 JVM 上,如果生成的类需要有无参数构造函数,就必须为属性指定默认值(见构造函数):
kotlin data class User(val name: String = "", val age: Int = 0)
在类体中声明的属性
编译器只使用主构造函数中定义的属性来生成自动函数。要把某个属性排除在生成的实现之外,请在类体中声明它:
| |
在下面的例子中,默认情况下只有 name 属性会被 toString()、equals()、hashCode() 和 copy() 的实现使用,并且只有一个组件函数 component1()。age 属性声明在类体中,因此被排除在外。所以,两个 name 相同但 age 不同的 Person 对象会被视为相等,因为 equals() 只计算主构造函数中的属性:
| |
复制
使用 copy() 函数可以复制对象,让你在保持其余属性不变的同时修改其部分属性。上面 User 类的该函数实现如下:
| |
然后你就可以这样写:
| |
copy() 函数创建的是实例的浅复制。换句话说,它不会递归复制各个组成部分。因此,对其他对象的引用是共享的。
例如,如果某个属性持有可变列表,那么通过"原始"值所做的修改在副本中也能看到,通过副本所做的修改在原始值中也能看到:
| |
可以看到,修改 duplicate.roles 属性同时也会改变 original.roles 属性,因为这两个属性共享同一个列表引用。
数据类与解构声明
为数据类生成的组件函数使得它们可以用于解构声明:
| |
标准数据类
标准库提供了 Pair 和 Triple 类。不过在大多数情况下,具名数据类是更好的设计选择,因为它们为属性提供了有意义的名称,让代码更易读。