在Java中复制HashMap

2023/06/07

1. 概述

在本教程中,我们将探讨HashMap的浅拷贝和深拷贝的概念,以及在Java中拷贝HashMap的几种技术。

我们还将考虑一些可以在特定情况下帮助我们的外部库。

2. 浅拷贝与深拷贝

首先,让我们了解一下HashMaps中浅拷贝和深拷贝的概念。

2.1 浅拷贝

HashMap的浅表副本是一个新的HashMap,它映射到与原始HashMap相同的键和值对象

例如,我们将创建一个Employee类,然后创建一个以Employee实例作为值的Map:

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);

现在,我们将验证原始Map及其浅表副本是不同的对象:

HashMap<String, Employee> shallowCopy = // shallow copy implementation
assertThat(shallowCopy).isNotSameAs(map);

由于这是一个浅拷贝,因此如果我们改变一个Employee实例的属性,它会影响原始Map和它的浅拷贝:

emp1.setFirstName("Johny");
assertThat(shallowCopy.get("emp1")).isEqualTo(map.get("emp1"));

2.2 深拷贝

HashMap的深拷贝是一个新的HashMap,可以深度复制所有映射。因此,它为所有键、值和映射创建新对象。

在这里,显式修改映射(键值)不会影响深拷贝:

HashMap<String, Employee> deepCopy = // deep copy implementation

emp1.setFirstName("Johny");

assertThat(deepCopy.get("emp1")).isNotEqualTo(map.get("emp1"));

3. HashMap接口

3.1 使用HashMap构造函数

HashMap的参数化构造函数HashMap(Map<? extends K, ? extends V> m)提供了一种浅拷贝整个Map的快速方法

HashMap<String, Employee> shallowCopy = new HashMap<String, Employee>(originalMap);

3.2 使用Map.clone()

与构造函数类似,HashMap#clone方法也创建了一个快速的浅拷贝:

HashMap<String, Employee> shallowCopy = originalMap.clone();

3.3 使用Map.put()

通过遍历每个条目并在另一个Map上调用put()方法,可以轻松地浅拷贝HashMap:

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 使用Map.putAll()

我们可以使用putAll()方法,而不是遍历所有条目,该方法一步浅拷贝所有映射:

HashMap<String, Employee> shallowCopy = new HashMap<>();
shallowCopy.putAll(originalMap);

我们应该注意,如果有匹配的键,put()和putAll()会替换值

有趣的是,如果我们查看HashMap的构造函数clone()和putAll()实现,我们会发现它们都使用相同的内部方法来复制条目—putMapEntries()。

4. 使用Java 8 Stream API复制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

使用Guava Maps,我们可以轻松创建不可变Map,以及排序和双向Map。要对这些Map中的任何一个进行不可变的浅拷贝,我们可以使用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

现在,Java没有任何内置的深度复制实现。因此,要进行深拷贝,我们可以覆盖clone()方法或使用序列化-反序列化技术。

Apache Commons有SerializationUtils和clone()方法来创建深层副本。为此,任何要包含在深拷贝中的类都必须实现Serializable接口:

public class Employee implements Serializable {
    // implementation details
}

HashMap<String, Employee> deepCopy = SerializationUtils.clone(originalMap);

7. 总结

在这个快速教程中,我们了解了在Java中复制HashMap的各种技术,以及HashMap的浅拷贝和深拷贝的概念。

此外,我们探讨了一些非常适合创建浅拷贝和深拷贝的外部库。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章