Kotlin 2.1.0 入门教程(二十一)数据类

数据类

数据类主要用于存储数据。

对于每个数据类,编译器会自动生成一些额外的成员函数,这些函数支持将实例打印为易读的输出、比较实例、复制实例等操作。

数据类使用 data 关键字标记:

kotlin 复制代码
data class User(val name: String, val age: Int)

编译器会根据主构造函数中声明的所有属性,自动派生以下成员:

  • equals() / hashCode() 对。

  • 格式为 User(name=John, age=42)toString() 函数。

  • 与属性声明顺序相对应的 componentN() 函数。

  • copy() 函数(详见下文)。

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

  • 主构造函数必须至少有一个参数。

  • 主构造函数的所有参数都必须标记为 valvar

  • 数据类不能是 abstract(抽象的)、open(开放的)、sealed(密封的)或 inner(内部的)。

此外,关于数据类成员的继承,其生成遵循以下规则:

  • 如果数据类主体中有 equals()hashCode()toString() 的显式实现,或者超类中有这些函数的 final 实现,那么不会生成这些函数,而是使用现有的实现。

  • 如果超类型有 open(开放的)且返回兼容类型的 componentN() 函数,那么会为数据类生成相应的函数,并覆盖超类型的这些函数。如果由于签名不兼容或超类型的函数是 final 而无法覆盖,将会报错。

  • 不允许为 componentN()copy() 函数提供显式实现。

数据类可以继承其他类。

kotlin 复制代码
open class Person(val name: String) {
    open fun introduce() {
        println("My name is $name.")
    }
}

// 定义一个继承自 Person 的数据类。
data class Employee(val id: Int, val name2: String, val department: String) : Person(name2) {
    override fun introduce() {
        super.introduce()
        println("I'm an employee with ID $id, working in the $department department.")
    }
}

fun main() {
    // 创建 Employee 数据类的实例。
    val employee = Employee(1, "John", "IT")

    // My name is John.
    // I'm an employee with ID 1, working in the IT department.
    employee.introduce()

    println(employee) // Employee(id=1, name2=John, department=IT)
    
    // 创建另一个相同属性的 Employee 实例。
    val anotherEmployee = Employee(1, "John", "IT")
    
    // 比较两个实例是否相等。
    println("Are they equal? ${employee == anotherEmployee}") // Are they equal? true
}

JVM 上,如果生成的数据类需要有无参构造函数,那么必须为属性指定默认值:

kotlin 复制代码
data class User(val name: String = "", val age: Int = 0)

类体中声明的属性

编译器仅会使用主构造函数内定义的属性来自动生成相关函数。若要将某个属性排除在自动生成的实现之外,可在类体中声明该属性:

kotlin 复制代码
data class Person(val name: String) {
    var age: Int = 0
}

在以下示例中,toString()equals()hashCode()copy() 这些自动生成的实现默认仅使用 name 属性,并且只有一个组件函数 component1()age 属性是在类体中声明的,因此被排除在外。所以,两个 name 相同但 age 值不同的 Person 对象会被视为相等,因为 equals() 方法仅评估主构造函数中的属性:

kotlin 复制代码
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 类,该函数的实现如下:

kotlin 复制代码
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)

然后你就可以编写如下代码:

kotlin 复制代码
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)

数据类与解构声明

为数据类生成的组件函数 componentN() 使得数据类可以用于解构声明:

kotlin 复制代码
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // Jane, 35 years of age

标准数据类

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

相关推荐
安东尼肉店13 小时前
Android compose屏幕适配终极解决方案
android
2501_9160074713 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun14 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户20187928316718 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子18 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
phoneixsky18 小时前
Kotlin的各种上下文Receiver,到底怎么个事
kotlin
小趴菜822719 小时前
安卓接入Max广告源
android
齊家治國平天下19 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO19 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
heeheeai19 小时前
okhttp使用指南
okhttp·kotlin·教程