如何在 Java 中复制 HashMap(不是浅复制)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28288546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to copy HashMap (not shallow copy) in Java
提问by Mathis
I need to make a copy of HashMap<Integer, List<MySpecialClass> >
but when I change something in the copy I want the original to stay the same. i.e when I remove something from the List<MySpecialClass>
from the copy it stays in the List<MySpecialClass>
in the original.
我需要制作一份副本,HashMap<Integer, List<MySpecialClass> >
但是当我更改副本中的某些内容时,我希望原件保持不变。即,当我List<MySpecialClass>
从副本中删除某些内容时,它会保留在List<MySpecialClass>
原件中。
If I understand it correctly, these two methods create just shallow copy which is not what I want:
如果我理解正确,这两种方法只会创建浅拷贝,这不是我想要的:
mapCopy = new HashMap<>(originalMap);
mapCopy = (HashMap) originalMap.clone();
Am I right?
我对吗?
Is there a better way to do it than just iterate through all the keys and all the list items and copy it manually?
除了遍历所有键和所有列表项并手动复制之外,还有更好的方法吗?
采纳答案by rgettman
You're right that a shallow copy won't meet your requirements. It will have copies of the List
s from your original map, but those List
s will refer to the same List
objects, so that a modification to a List
from one HashMap
will appear in the corresponding List
from the other HashMap
.
你是对的,浅拷贝不能满足你的要求。它将拥有List
原始地图中 s 的副本,但这些List
s 将引用相同的List
对象,因此对一个List
from的修改HashMap
将出现在对应的List
from another 中HashMap
。
There is no deep copying supplied for a HashMap
in Java, so you will still have to loop through all of the entries and put
them in the new HashMap
. But you should also make a copy of the List
each time also. Something like this:
HashMap
在 Java 中没有为 a 提供深度复制,因此您仍然需要循环遍历所有条目和put
它们在新的HashMap
. 但是你也应该List
每次都复制一份。像这样的东西:
public static HashMap<Integer, List<MySpecialClass>> copy(
HashMap<Integer, List<MySpecialClass>> original)
{
HashMap<Integer, List<MySpecialClass>> copy = new HashMap<Integer, List<MySpecialClass>>();
for (Map.Entry<Integer, List<MySpecialClass>> entry : original.entrySet())
{
copy.put(entry.getKey(),
// Or whatever List implementation you'd like here.
new ArrayList<MySpecialClass>(entry.getValue()));
}
return copy;
}
If you want to modify your individual MySpecialClass
objects, and have the changes not be reflected in the List
s of your copied HashMap
, then you will need to make new copies of them too.
如果您想修改您的单个MySpecialClass
对象,并且更改不会反映在List
您复制的s 中HashMap
,那么您也需要制作它们的新副本。
回答by Brian
You are making a copy of the HashMap itself, so changing the HashMap copy will not change the original HashMap (i.e. adding or removing entries), but because the objects you have stored are not primitive types, the List that you retrieve with a given key will be the same whether retrieved from the first or the second Map.
您正在制作 HashMap 本身的副本,因此更改 HashMap 副本不会更改原始 HashMap(即添加或删除条目),但由于您存储的对象不是原始类型,因此您使用给定键检索的 List无论是从第一个 Map 还是从第二个 Map 检索,结果都是一样的。
Thus, there is still only ONE copy of that list, referenced by both maps: changing the List changes it no matter which reference you use to access it.
因此,仍然只有该列表的一个副本,由两个映射引用:无论您使用哪个引用访问它,更改列表都会更改它。
If you want the actual List to be a separate copy, you will have to do as you said: iterate over the entry set of the HashMap and create a copy of each List manually, adding it to the new map as you go.
如果您希望实际的 List 是一个单独的副本,则必须按照您说的那样进行:遍历 HashMap 的条目集并手动创建每个 List 的副本,并随时将其添加到新映射中。
If there is a better way than that, I don't know what it is.
如果有比这更好的方法,我不知道它是什么。
回答by Nabil Echaouch
You can try deep cloning. Have a look for example at https://code.google.com/p/cloning/
您可以尝试深度克隆。例如在https://code.google.com/p/cloning/
回答by sprinter
This does need iteration unfortunately. But it's pretty trivial with Java 8 streams:
不幸的是,这确实需要迭代。但是对于 Java 8 流来说,这很简单:
mapCopy = map.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> new ArrayList(e.getValue()));
Edit: in later versions of Java, e -> List.copyOf(e.getValue())
would be preferred.
编辑:在 Java 的更高版本中,e -> List.copyOf(e.getValue())
将是首选。
回答by neu242
Serialize to json and deserialize afterwards:
序列化为 json 并在之后反序列化:
Map<String, Object> originalMap = new HashMap<>();
String json = new Gson().toJson(originalMap);
Map<String, Object> mapCopy = new Gson().fromJson(
json, new TypeToken<Map<String, Object>>() {}.getType());
For special classes you might need to write a custom deserializer.
对于特殊类,您可能需要编写自定义反序列化器。