如何在Java中复制HashMap(不是浅拷贝)

我需要复制HashMap<Integer, List >但是当我在副本中更改某些内容时,我希望原始内容保持不变。 即,当我从副本中删除List中的某些内容时,它将保留在原始List中的List中。

如果我理解正确,这两个方法只会创建浅层副本,这不是我想要的:

 mapCopy = new HashMap(originalMap); mapCopy = (HashMap) originalMap.clone(); 

我对吗?

有没有比这更好的方法来迭代所有键和所有列表项并手动复制它?

你是对的,浅版不符合你的要求。 它将从原始映射中获得List的副本,但这些List将引用相同的List对象,因此从一个HashMapList的修改将出现在来自其他HashMap的相应List

在Java中没有为HashMap提供深度复制,因此您仍然需要遍历所有条目put它们放入新的HashMap 。 但是你也应该每次都复制一份List 。 像这样的东西:

 public static HashMap> copy( HashMap> original) { HashMap> copy = new HashMap>(); for (Map.Entry> entry : original.entrySet()) { copy.put(entry.getKey(), // Or whatever List implementation you'd like here. new ArrayList(entry.getValue())); } return copy; } 

如果要修改单个MySpecialClass对象,并且更改未反映在复制的HashMapList中,则还需要制作它们的新副本。

遗憾的是,这确实需要迭代。 但是Java 8流非常简单:

 mapCopy = map.entrySet().stream() .collect(Collectors.toMap(e -> e.getKey(), e -> new ArrayList(e.getValue())); 

编辑:在Java的更高版本中, e -> List.copyOf(e.getValue())将是首选。

你可以尝试深度克隆。 请访问https://code.google.com/p/cloning/查看示例

您正在制作HashMap本身的副本,因此更改HashMap副本不会更改原始HashMap(即添加或删除条目),但由于您存储的对象不是基本类型,因此使用给定键检索的List无论是从第一个地图还是第二个地图中检索,都是相同的。

因此,该列表仍然只有一个副本,由两个映射引用:无论您使用哪个引用来访问它,更改List都会更改它。

如果您希望实际的List是一个单独的副本,您将必须按照您的说法执行操作:迭代HashMap的条目集并手动创建每个List的副本,然后将其添加到新映射中。

如果有更好的方法,我不知道它是什么。

然后序列化为json并反序列化:

 Map originalMap = new HashMap<>(); String json = new Gson().toJson(originalMap); Map mapCopy = new Gson().fromJson( json, new TypeToken>() {}.getType()); 

对于特殊类,您可能需要编写自定义反序列化程序 。