为什么Java“ putAll”无法深度复制Map的值元素?

时间:2018-11-13 11:25:02

标签: java dictionary set copy clone

我得到了以下代码片段:

public static void main(String[] args){
    Map<String, Set<String>> map = new HashMap<>();
    Set<String> set = new HashSet<>();
    set.add("user1");
    set.add("user2");
    map.put("key1", set);

    Map<String, Set<String>> map2 = new HashMap<>();
    map2.putAll(map);// I expect all elements are copied

    map.get("key1").add("user3");// add 1 element in "map"
    System.out.println(map2.get("key1").size()); // "map2" was affected
}

实际上,对地图set元素的修改会影响map2,因此程序将打印“ 3”而不是“ 2”

这很奇怪,我希望只要在新的map2结构中使用“ putAll”方法,我都认为键和值都应该被深克隆?

如何在复制地图中的所有元素的同时修复程序并确保map2已从map中分割出来?

谢谢

2 个答案:

答案 0 :(得分:6)

putAll复制键和值的引用。它不会复制那些引用所引用的实例。

您必须循环(或流式传输)原始的Map并创建所有值Set的副本:

Map<String, Set<String>> map2 =
    map.entrySet()
       .stream()
       .collect(Collectors.toMap(Map.Entry::getKey,e-> new HashSet<>(e.getValue())));

请注意,由于String是不可变的,因此无需创建密钥的副本。

答案 1 :(得分:1)

Another way:

Map<String, Set<String>> map2 = new HashMap<>();
map2.putAll(map);

map2.replaceAll((k, v) -> new HashSet<>(v));