Menu
CoddyTech

数据类

本课属于 Coddy Kotlin 学习旅程的“面向对象编程”单元。第 32 课,共 57 课。

数据类是一种主要用于保存数据的类。data 修饰符会让编译器根据主构造函数的属性生成 toString()、equals()、hashCode()、copy() 和 componentN():

data class Point(val x: Int, val y: Int)

在 main 中:

val a = Point(1, 2)
val b = Point(1, 2)
println(a)
println(a == b)
println(setOf(a, b).size)

输出:

Point(x=1, y=2)
true
1

如果没有 data,println 会显示类名和哈希码,例如 Point@1b6d3586,而两个值相同的对象并不相等。copy() 会创建一个更改了某些属性的新对象,并保留原对象不变,因此具有 val 属性的数据类可以作为不可变值使用:

data class User(val name: String, val email: String, val admin: Boolean = false)

在 main 中:

val ada = User("Ada", "ada@example.com")
val boss = ada.copy(admin = true)
println(ada)
println(boss)
println(ada == boss)

输出:

User(name=Ada, email=ada@example.com, admin=false)
User(name=Ada, email=ada@example.com, admin=true)
false

解构声明会将对象解包为变量:val (x, y) = point 会按构造函数中的顺序调用生成的 component1() 和 component2()。它也适用于 for 循环和 lambda 参数,使用 _ 可以跳过一个属性:

data class Score(val player: String, val points: Int, val level: Int)

在 main 中:

val scores = listOf(Score("ada", 120, 3), Score("bo", 95, 2))
for ((player, points) in scores) println("$player: $points")
val (_, bestPoints, bestLevel) = scores.maxBy { it.points }
println("best: $bestPoints at level $bestLevel")

输出:

ada: 120
bo: 95
best: 120 at level 3

只有主构造函数中的属性会参与其中:在类体中声明的属性不会包含在 toString、equals、hashCode 和 copy 中。数据类至少需要一个构造函数参数,并且每个参数都必须是 val 或 var:

data class Reading(val sensor: String, val value: Int) {
    var note = ""
}

在 main 中:

val r1 = Reading("t1", 20)
val r2 = Reading("t1", 20)
r1.note = "checked"
println(r1)
println(r1 == r2)

输出:

Reading(sensor=t1, value=20)
true
challenge icon

挑战

简单

将 Book 设为 data class,这样打印和比较时会按值进行。然后完成三个函数:parse(line) 将 Dune;Herbert;1965 转换为 Book,newEdition(book, year) 返回一个副本,其中年份为新年份,标题中还添加了 (new edition),而 describe(book) 使用解构声明返回 Dune by Herbert, 1965。

提供的代码会解析每一行输入,打印每本书、重复项的数量、第一本书的新版本(年份为 2024),以及每本不同书的描述。

你的代码写在 Book.kt 和 BookTools.kt 中。Main.kt 存放提供的输入/输出代码,不能编辑。

亲手试试

fun main() {
    // 提供的输入/输出代码:保持原样
    val input = generateSequence(::readLine).toList()
    val books = input.map { parse(it) }
    for (b in books) println(b)
    println("duplicates: ${books.size - books.distinct().size}")
    println(newEdition(books[0], 2024))
    for (b in books.distinct()) println(describe(b))
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Kotlin 在线编辑器