1. 概述
本文将介绍在 Kotlin 中如何将一个 Map
的所有条目复制到另一个 Map
中的几种常用方法。这类操作在实际开发中很常见,比如缓存处理、配置传递或避免共享可变状态时的“踩坑”场景。
核心目标是:✅ 安全地复制数据,避免意外的引用共享 ❌
2. 复制 Map 的方法
从 Kotlin 1.1 开始,标准库提供了简洁高效的扩展函数来实现 Map 复制。以下是主流做法:
✅ 使用 toMap()
创建不可变副本
val bookInfo = mapOf("name" to "1984", "author" to "Orwell")
val copied = bookInfo.toMap()
assertThat(copied).isNotSameAs(bookInfo) // 是不同对象
assertThat(copied).containsAllEntriesOf(bookInfo) // 内容一致
⚠️ 注意:通过
mapOf()
或toMap()
得到的是 不可变 Map(Immutable Map),无法添加/删除条目。
✅ 使用 toMutableMap()
创建可变副本
如果需要后续修改副本内容,应使用:
val mutableCopy = bookInfo.toMutableMap()
assertThat(mutableCopy).containsAllEntriesOf(bookInfo)
// 可以安全修改
mutableCopy["year"] = "1949"
这样得到的是 MutableMap
,适用于需要动态增删的场景。
✅ 复制到已有 Map 实例
还可以把源 Map 的内容填充进一个已存在的 MutableMap
:
val destination = mutableMapOf<String, String>()
bookInfo.toMap(destination) // 注意:此处调用的是带参数的 toMap
assertThat(destination).containsAllEntriesOf(bookInfo)
该方法适用于资源复用或批量合并场景,避免频繁创建新对象。
✅ 兼容旧版本 Kotlin:直接使用 HashMap 构造器
在 Kotlin 1.1 之前,可以借助 Java 的 HashMap
构造函数:
val copied = java.util.HashMap(bookInfo)
assertThat(copied).containsAllEntriesOf(bookInfo)
这种方式依然有效,尤其在与 Java 互操作或低版本环境中有用。
3. 重要提醒:这是浅拷贝!
⚠️ 所有上述方法都只进行 浅拷贝(shallow copy)。这意味着:
- 两个 Map 是不同的容器对象(引用不同)
- 但它们存储的 值对象是同一个实例
示例验证:
assertSame(copied["name"], bookInfo["name"]) // ✅ 引用相同
📌 如果 Map 的 value 是可变对象(如自定义类实例),修改副本中的 value 会影响原始 Map —— 这是常见的“踩坑点”!
data class Book(var title: String)
val original = mapOf("b1" to Book("1984"))
val shallowCopy = original.toMutableMap()
shallowCopy["b1"]?.title = "Animal Farm"
println(original["b1"]?.title) // 输出: Animal Farm → 原始数据被改了!
✅ 如需深拷贝,必须手动实现或借助序列化工具(如 Jackson、Kryo 等)。
4. 总结
方法 | 是否可变 | 适用场景 |
---|---|---|
toMap() |
否 | 创建不可变快照 |
toMutableMap() |
是 | 需要后续修改的副本 |
toMap(destination) |
是 | 填充已有容器,节省内存 |
HashMap(source) |
是 | 兼容老版本或明确使用 HashMap |
📌 核心建议:
- 优先使用 Kotlin 扩展函数,代码更简洁、语义清晰
- 注意浅拷贝限制,复杂对象务必考虑深拷贝需求
- 不可变性优先:能用
mapOf
/toMap
就不用可变 Map,减少副作用
完整示例代码见 GitHub 仓库。