1. Overview
1.概述
In this tutorial, we’ll explore the concept of a shallow vs deep copy of a HashMap along with several techniques to copy a HashMap in Java.
在本教程中,我们将探讨HashMap的浅层与深层拷贝的概念,以及在Java中复制HashMap的几种技术。
We’ll also consider some of the external libraries that can help us in specific cases.
我们还将考虑一些能在特定情况下帮助我们的外部库。
2. Shallow vs Deep Copies
2.浅层拷贝与深层拷贝
Firstly, let’s understand the concept of shallow and deep copies in HashMaps.
首先,让我们了解一下HashMaps中浅层和深层拷贝的概念。
2.1. Shallow Copy
2.1.浅层复制
A shallow copy of a HashMap is a new HashMap with mappings to the same key and value objects as the original HashMap.
一个HashMap的浅层拷贝是一个新的HashMap,其键和值对象的映射与原HashMap相同。
For example, we’ll create an Employee class and then a map with Employee instances as values:
例如,我们将创建一个Employee类,然后创建一个以Employee实例为值的地图。
public class Employee {
private String name;
// constructor, getters and setters
}
HashMap<String, Employee> map = new HashMap<>();
Employee emp1 = new Employee("John");
Employee emp2 = new Employee("Norman");
map.put("emp1", emp1);
map.put("emp2", emp2);
Now, we’ll verify that the original map and its shallow copy are different objects:
现在,我们将验证原始地图和它的浅层拷贝是不同的对象。
HashMap<String, Employee> shallowCopy = // shallow copy implementation
assertThat(shallowCopy).isNotSameAs(map);
Because this is a shallow copy, if we change an Employee instance’s properties, it will affect both the original map and its shallow copy:
因为这是一个浅层拷贝,如果我们改变一个Employee实例的属性,它将同时影响原始地图和其浅层拷贝。
emp1.setFirstName("Johny");
assertThat(shallowCopy.get("emp1")).isEqualTo(map.get("emp1"));
2.2. Deep Copy
2.2.深度复制
A deep copy of a HashMap is a new HashMap that deeply copies all the mappings. Therefore, it creates new objects for all keys, values, and mappings.
一个HashMap的深度拷贝是一个新的HashMap,它深度拷贝了所有的映射。因此,它为所有键、值和映射创建了新的对象。
Here, explicitly modifying the mappings (key-values) will not affect the deep copy:
在这里,明确地修改映射(键值)不会影响深度拷贝。
HashMap<String, Employee> deepCopy = // deep copy implementation
emp1.setFirstName("Johny");
assertThat(deepCopy.get("emp1")).isNotEqualTo(map.get("emp1"));
3. HashMap API
3. API
3.1. Using the HashMap Constructor
3.1.使用HashMap C构造器
HashMap‘s parameterized constructor HashMap(Map<? extends K,? extends V> m) provides a quick way to shallow copy an entire map:
HashMap的参数化构造函数HashMap(Map<?extends K, ?extends V> m) 提供了一个快速的方法来浅层复制整个地图:。
HashMap<String, Employee> shallowCopy = new HashMap<String, Employee>(originalMap);
3.2. Using Map.clone()
3.2.使用Map.clone()
Similar to the constructor, the HashMap#clone method also creates a quick shallow copy:
与构造函数类似,HashMap#clone方法也创建一个快速的浅层拷贝。
HashMap<String, Employee> shallowCopy = originalMap.clone();
3.3. Using Map.put()
3.3.使用Map.put()
A HashMap can easily be shallow-copied by iterating over each entry and calling the put() method on another map:
HashMap可以通过迭代每个条目并在另一张地图上调用put()方法来轻松地进行浅层复制。
HashMap<String, Employee> shallowCopy = new HashMap<String, Employee>();
Set<Entry<String, Employee>> entries = originalMap.entrySet();
for (Map.Entry<String, Employee> mapEntry : entries) {
shallowCopy.put(mapEntry.getKey(), mapEntry.getValue());
}
3.4. Using Map.putAll()
3.4.使用Map.putAll()
Instead of iterating through all of the entries, we can use the putAll() method, which shallow-copies all of the mappings in one step:
我们可以使用putAll()方法,而不是遍历所有的条目,该方法在一个步骤中浅层复制所有的映射关系。
HashMap<String, Employee> shallowCopy = new HashMap<>();
shallowCopy.putAll(originalMap);
We should note that put() and putAll() replace the values if there is a matching key.
我们应该注意到,put()和putAll()如果有一个匹配的键,就会替换这些值。
It’s also interesting to note that, if we look at the HashMap‘s constructor, clone(), and putAll() implementation, we’ll find all of them use the same internal method to copy entries — putMapEntries().
同样有趣的是,如果我们看一下HashMap的构造函数、clone()和putAll()的实现,我们会发现它们都使用相同的内部方法来复制条目 – putMapEntries()。
4. Copying HashMap Using the Java 8 Stream API
4.复制HashMap使用Java 8 Stream API
We can use the Java 8 Stream API to create a shallow copy of a HashMap:
我们可以使用Java 8 Stream API来创建一个HashMap的浅层拷贝。
Set<Entry<String, Employee>> entries = originalMap.entrySet();
HashMap<String, Employee> shallowCopy = (HashMap<String, Employee>) entries.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
5. Google Guava
5.谷歌番石榴
Using Guava Maps, we can easily create immutable maps, along with the sorted and bi map. To make an immutable, shallow copy of any of these maps, we can use the copyOf method:
使用Guava地图,我们可以很容易地创建不可变的地图,以及排序的地图和bi地图。要对这些地图中的任何一个做一个不可变的浅层拷贝,我们可以使用copyOf方法。
Map<String, Employee> map = ImmutableMap.<String, Employee>builder()
.put("emp1",emp1)
.put("emp2",emp2)
.build();
Map<String, Employee> shallowCopy = ImmutableMap.copyOf(map);
assertThat(shallowCopy).isSameAs(map);
6. Apache Commons Lang
6.阿帕奇公社朗
Now, Java doesn’t have any built-in deep copy implementations. So to make a deep copy, either we can override the clone() method or use a serialization-deserialization technique.
现在,Java没有任何内置的深度复制实现。因此,为了进行深度复制,我们可以覆盖clone()方法或者使用序列化-反序列化技术。
Apache Commons has SerializationUtils with a clone() method to create a deep copy. For this, any class to be included in deep copy must implement the Serializable interface:
Apache Commons的SerializationUtils有一个clone()方法来创建一个深度拷贝。为此,任何要包含在深度拷贝中的类必须实现Serializable接口。
public class Employee implements Serializable {
// implementation details
}
HashMap<String, Employee> deepCopy = SerializationUtils.clone(originalMap);
7. Conclusion
7.结语
In this quick tutorial, we’ve seen various techniques to copy a HashMap in Java, along with the concept of shallow and deep copy for HashMaps.
在这个快速教程中,我们看到了在Java中复制HashMap的各种技术,以及HashMap的浅层和深层复制的概念。
Also, we explored some of the external libraries that are quite handy for creating shallow and deep copies.
此外,我们还探索了一些对创建浅层和深层拷贝相当方便的外部库。
The complete source code of these implementations along with the unit tests are available in the GitHub project.
这些实现的完整源代码以及单元测试都可以在GitHub项目中找到。