Kotlin Academy · 课时

集合中的数据类与作为 Map 键

利用结构相等性在集合和映射中使用数据类。

第 4 / 4 课13 个步骤

集合中的数据类与作为 Map 键 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。

作为数值对象的数据类

由于数据类会按结构重写 equals 和 hashCode,因此它们可以完美地用于集合和映射键,不同于普通类。

普通类:不适合作为映射键

普通类默认使用引用相等性。两个看起来相等的对象实际上是不同的映射键。
class Key(val id: Int)  // no equals/hashCode
val map = mutableMapOf<Key, String>()
val k1 = Key(1)
val k2 = Key(1)  // same id, different object
map[k1] = "value"
println(map[k2])  // null! k2 != k1 by reference

数据类:正确的映射键

数据类使用结构相等性。只要两个对象的属性相同,它们就是相等的。
data class Key(val id: Int)
val map = mutableMapOf<Key, String>()
val k1 = Key(1)
val k2 = Key(1)
map[k1] = "value"
println(map[k2])  // "value"! Equal by value

集合中的数据类

集合使用 equals 和 hashCode 去重。数据类可以正确完成去重。
data class Tag(val name: String)
val tags = mutableSetOf<Tag>()
tags.add(Tag("kotlin"))
tags.add(Tag("kotlin"))  // duplicate
tags.add(Tag("java"))
println(tags.size)  // 2 (not 3)

使用 GroupBy 处理数据类

按数据类键对集合进行分组。
data class Category(val name: String, val parent: String)
val items = listOf(
    "List" to Category("Collections", "stdlib"),
    "Map" to Category("Collections", "stdlib"),
    "Flow" to Category("Coroutines", "kotlinx")
)
val grouped = items.groupBy { it.second }
println(grouped.keys.size)  // 2

使用映射统计出现次数

使用数据类作为映射键,统计结构化数据的出现次数。
data class Pair2(val x: Int, val y: Int)
val points = listOf(Pair2(1,2), Pair2(1,2), Pair2(3,4))
val counts = points.groupingBy { it }.eachCount()
println(counts)  // {Pair2(x=1, y=2)=2, Pair2(x=3, y=4)=1}

嵌套数据类

数据类可以包含其他数据类。对于嵌套的数据类,equals 和 hashCode 会进行深层比较。
data class Address(val city: String, val country: String)
data class Person(val name: String, val address: Address)
val p1 = Person("Alice", Address("Berlin", "DE"))
val p2 = Person("Alice", Address("Berlin", "DE"))
println(p1 == p2)  // true

使用 sortedBy 处理数据类

按某个属性对数据类实例列表进行排序。
data class Student(val name: String, val grade: Double)
val students = listOf(
    Student("Bob", 3.2),
    Student("Alice", 3.8),
    Student("Charlie", 2.9)
)
println(students.sortedBy { it.grade })

数据类与缓存

当缓存键由多个部分组成时,可以将数据类用作 HashMap 的缓存键。
data class CacheKey(val userId: Long, val resourceType: String)
val cache = HashMap<CacheKey, ByteArray>()
val key = CacheKey(42, "avatar")
cache[key] = byteArrayOf(1, 2, 3)
println(cache[CacheKey(42, "avatar")] != null)  // true

数据类上的 distinct

对数据类列表调用 distinct() 时,会使用它们的 equals 移除重复项。
data class Event(val type: String, val ts: Long)
val events = listOf(
    Event("click", 1000),
    Event("click", 1000),  // duplicate
    Event("scroll", 2000)
)
println(events.distinct().size)  // 2

不可变键更安全

始终使用具有 val 属性的数据类作为映射键或集合元素。插入后修改键会破坏数据结构。
data class ImmutableKey(val id: Int)  // val properties only
// DON'T: data class MutableKey(var id: Int)  // changing id breaks map!

快速检查

为什么数据类可以正确用作映射键,而普通类通常不行?

回顾

数据类拥有正确的结构化 equals/hashCode,因此可以用作映射键和集合元素。使用 val 属性使键保持不可变。结合数据类使用 groupBy、distinct 和 sortedBy,可以实现强大的查询。
免费开始

用 AI 导师学习 Kotlin — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
51
课程
203

常见问题解答

「集合中的数据类与作为 Map 键」课时是免费的吗?

是的 — 「集合中的数据类与作为 Map 键」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。

「集合中的数据类与作为 Map 键」这节课中我会学到什么?

利用结构相等性在集合和映射中使用数据类。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Kotlin Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「集合中的数据类与作为 Map 键」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Kotlin Academy 课中编写并运行代码吗?

能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 数据类基础:自动生成的方法
  2. 使用 copy() 复制与部分覆盖
  3. 使用 componentN 进行解构声明
  4. 集合中的数据类与作为 Map 键
← 返回 Kotlin Academy