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 仓库


原始标题:Copy a Map in Kotlin