1. 概述
本文将深入探讨 Java 中 HashMap 的浅拷贝与深拷贝概念,并提供多种实用的 HashMap 拷贝方法。
同时也会介绍一些第三方库,它们在某些场景下能帮助我们更高效地完成拷贝操作。
2. 浅拷贝 vs 深拷贝
在开始具体实现前,先明确 HashMap 浅拷贝与深拷贝的本质区别。
2.1 浅拷贝
✅ 浅拷贝指的是创建一个新的 HashMap,但其中的 key 和 value 都是指向原 HashMap 中对象的引用。
举个例子,我们定义一个 Employee
类,并将其作为 value 存入 HashMap:
public class Employee {
private String name;
// 构造方法、getter 和 setter 省略
}
初始化 HashMap:
HashMap<String, Employee> map = new HashMap<>();
Employee emp1 = new Employee("John");
Employee emp2 = new Employee("Norman");
map.put("emp1", emp1);
map.put("emp2", emp2);
浅拷贝后,验证是否是不同对象:
HashMap<String, Employee> shallowCopy = new HashMap<>(map); // 示例浅拷贝方式
assertThat(shallowCopy).isNotSameAs(map);
⚠️ 但因为是浅拷贝,如果我们修改了原始对象的属性,拷贝后的 map 也会受到影响:
emp1.setName("Johny");
assertThat(shallowCopy.get("emp1")).isEqualTo(map.get("emp1"));
2.2 深拷贝
✅ 深拷贝会创建一个全新的 HashMap,并且对每个 key 和 value 都进行深度复制,即创建新对象。
这样,即使修改原始对象,深拷贝后的 map 也不会受影响:
HashMap<String, Employee> deepCopy = deepCopyImplementation(map); // 示例深拷贝方式
emp1.setName("Johny");
assertThat(deepCopy.get("emp1")).isNotEqualTo(map.get("emp1"));
3. 使用 HashMap 原生 API 拷贝
3.1 使用 HashMap 构造函数
HashMap 提供了一个带 Map 参数的构造函数,可以快速完成浅拷贝:
HashMap<String, Employee> shallowCopy = new HashMap<>(originalMap);
3.2 使用 clone() 方法
HashMap 的 clone 方法也返回一个浅拷贝:
HashMap<String, Employee> shallowCopy = originalMap.clone();
3.3 使用 put() 方法逐个添加
通过遍历 entrySet 并逐个 put 到新 map 中:
HashMap<String, Employee> shallowCopy = new HashMap<>();
for (Map.Entry<String, Employee> entry : originalMap.entrySet()) {
shallowCopy.put(entry.getKey(), entry.getValue());
}
3.4 使用 putAll() 方法
更简洁的方式是使用 putAll(),一次性拷贝所有映射:
HashMap<String, Employee> shallowCopy = new HashMap<>();
shallowCopy.putAll(originalMap);
⚠️ 注意:put()
和 putAll()
都会覆盖已有 key 的值。
另外,HashMap 构造函数、clone()、putAll() 内部都调用了同一个方法 putMapEntries()
。
4. 使用 Java 8 Stream API 拷贝
✅ 可以使用 Java 8 的 Stream API 来完成 HashMap 的浅拷贝:
HashMap<String, Employee> shallowCopy = originalMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
⚠️ 注意:Collectors.toMap
返回的是 Map
类型,需要强制转换为 HashMap
。
5. 使用 Google Guava
Google Guava 提供了丰富的 Map 工具类,可以方便地创建不可变的浅拷贝:
Map<String, Employee> originalMap = ImmutableMap.<String, Employee>builder()
.put("emp1", emp1)
.put("emp2", emp2)
.build();
Map<String, Employee> shallowCopy = ImmutableMap.copyOf(originalMap);
assertThat(shallowCopy).isSameAs(originalMap); // 不可变 map 的 copyOf 可能直接返回原对象
6. 使用 Apache Commons Lang 深拷贝
❌ Java 原生没有提供深拷贝实现。
✅ Apache Commons Lang 提供了 SerializationUtils.clone()
方法,可用于深拷贝,前提是类实现了 Serializable
接口:
public class Employee implements Serializable {
private String name;
// 构造方法、getter 和 setter 省略
}
进行深拷贝:
HashMap<String, Employee> deepCopy = SerializationUtils.clone(originalMap);
⚠️ 注意:该方法依赖对象序列化,性能较低,适合结构复杂、需要真正深拷贝的场景。
7. 总结
方法 | 类型 | 是否支持深拷贝 | 备注 |
---|---|---|---|
构造函数 | 浅拷贝 | ❌ | 简单高效 |
clone() | 浅拷贝 | ❌ | 简洁 |
putAll() | 浅拷贝 | ❌ | 推荐方式 |
Stream API | 浅拷贝 | ❌ | 函数式风格 |
Guava | 浅拷贝 | ❌ | 适合不可变 map |
Apache Commons Lang | 深拷贝 | ✅ | 需实现 Serializable |
📌 根据实际需求选择合适的拷贝方式,避免不必要的性能开销。对于深拷贝,建议根据业务场景选择序列化、手动 clone 或第三方库。
完整的示例代码及单元测试可在 GitHub 仓库 中查看。