18:kotlin 类和对象 -- 数据类(Data classes)

数据类是其主要目的是保存数据的类。数据类会自动附带额外的成员方法

使用data声明一个数据类

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)

数据类成员的生成遵循以下规则,涉及成员的继承:

  • 如果在数据类中有 .equals().hashCode().toString() 的显式实现,或者在超类中有这些方法的最终实现,则不会生成这些方法,而是使用现有的实现
  • 如果父类(超类型)有 .componentN() 方法,并且这些方法是open的,同时返回的类型与数据类兼容,那么数据类会为这些方法生成相应的实现,并覆盖超类型的方法。如果由于不兼容返回值或者使用final修饰而导致超类型的方法无法被覆盖,则会报告错误。
  • 不允许为 .componentN() .copy() 方法提供显式实现。

在JVM上如果需要一个无参构造函数,需要给主构造函数的参数指定默认值

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

类主体中声明的属性

编译器仅在自动生成的函数中使用主构造函数内定义的属性。要从生成的实现中排除某个属性,请将其声明在类体内

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

在这个例子中,只有 name属性可以在 .toString().equals().hashCode().copy() 的实现中使用,而且只有一个名为 .component1() 的分量函数。age 属性不能在这些实现中使用,因为它是在类体内声明的。如果两个 Person 对象具有不同的年龄但相同的名称,那么它们会被视为相等。这是因为.equals()函数只能检查name属性的相等性。

fun main() {
    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)
}

拷贝

使用.copy()函数来复制一个对象,允许您更改其中一些属性而保持其余部分不变。对于 User 类的.copy()函数实现如下

data class User(val name: String = "", val age: Int = 0)
// fun copy(name: String = this.name, age: Int = this.age) = User(name, age)

fun main() {
    val user = User("John")
    val copy = user.copy(age = 2)
    println(user)   // User(name=John, age=0)
    println(copy)   // User(name=John, age=2)
}

数据类和解构声明

为数据类生成的分量函数(Component functions)使得可以在解构声明(destructuring declarations)中使用它们

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

结构函数依赖于.componentN()方法,因此只有在主构造函数中的参数才能使用结构函数

标准数据类

标准库提供了PairTriple类。然而,在大多数情况下,使用具有命名属性的数据类是更好的设计选择,因为它们通过为属性提供有意义的名称使代码更易读。
作者

  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值