如何在 Java 中复制 HashMap(不是浅拷贝)
How to copy HashMap (not shallow copy) in Java
我需要制作 HashMap<Integer, List<MySpecialClass> >
的副本,但是当我更改副本中的某些内容时,我希望原件保持不变。即当我从副本的 List<MySpecialClass>
中删除某些内容时,它会保留在原件的 List<MySpecialClass>
中。
如果我理解正确,这两种方法创建的只是浅拷贝,这不是我想要的:
mapCopy = new HashMap<>(originalMap);
mapCopy = (HashMap) originalMap.clone();
我说得对吗?
有没有比遍历所有键和所有列表项并手动复制更好的方法?
您正在复制 HashMap 本身,因此更改 HashMap 副本不会更改原始 HashMap(即添加或删除条目),但由于您存储的对象不是原始类型,因此您创建的 List无论是从第一个还是第二个 Map 中检索,使用给定键检索都是相同的。
因此,仍然只有该列表的一个副本,由两个地图引用:无论您使用哪个引用访问它,更改列表都会改变它。
如果你希望实际的List是一个单独的副本,你必须按照你说的做:遍历HashMap的条目集并手动创建每个List的副本,将其添加到新映射中你去吧
如果有比这更好的方法,我不知道是什么
你说得对,浅拷贝不能满足你的要求。它将包含原始地图中 List
的副本,但那些 List
将引用相同的 List
对象,因此从一个 List
修改为 List
HashMap
会出现在对应的List
中,来自另一个HashMap
。
没有为 Java 中的 HashMap
提供深度复制,因此您仍然需要遍历所有条目并 put
它们在新的 [=15] 中=].但是你也应该每次都复制一份 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;
}
如果您想要修改您的个人 MySpecialClass
对象,并且不让更改反映在您复制的 HashMap
的 List
中,那么您将需要创建新的他们的副本也是。
不幸的是,这确实需要迭代。但是对于 Java 8 个流来说,这是非常微不足道的:
mapCopy = map.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> List.copyOf(e.getValue())))
序列化为 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());
对于特殊的 类,您可能需要 write a custom deserializer。
只需使用 Apache Commons Lang - SerializationUtils.clone();
像这样:
Map<String, List<MySpecialClass>> originalMap = new HashMap();
HashMap<String, List<MySpecialClass>> deepCopy = SerializationUtils.clone(new HashMap<>(originalMap));
还要确保 MySpecialClass 实现了 Serializable 接口。
public class MySpecialClass implements Serializable{}
我需要制作 HashMap<Integer, List<MySpecialClass> >
的副本,但是当我更改副本中的某些内容时,我希望原件保持不变。即当我从副本的 List<MySpecialClass>
中删除某些内容时,它会保留在原件的 List<MySpecialClass>
中。
如果我理解正确,这两种方法创建的只是浅拷贝,这不是我想要的:
mapCopy = new HashMap<>(originalMap);
mapCopy = (HashMap) originalMap.clone();
我说得对吗?
有没有比遍历所有键和所有列表项并手动复制更好的方法?
您正在复制 HashMap 本身,因此更改 HashMap 副本不会更改原始 HashMap(即添加或删除条目),但由于您存储的对象不是原始类型,因此您创建的 List无论是从第一个还是第二个 Map 中检索,使用给定键检索都是相同的。
因此,仍然只有该列表的一个副本,由两个地图引用:无论您使用哪个引用访问它,更改列表都会改变它。
如果你希望实际的List是一个单独的副本,你必须按照你说的做:遍历HashMap的条目集并手动创建每个List的副本,将其添加到新映射中你去吧
如果有比这更好的方法,我不知道是什么
你说得对,浅拷贝不能满足你的要求。它将包含原始地图中 List
的副本,但那些 List
将引用相同的 List
对象,因此从一个 List
修改为 List
HashMap
会出现在对应的List
中,来自另一个HashMap
。
没有为 Java 中的 HashMap
提供深度复制,因此您仍然需要遍历所有条目并 put
它们在新的 [=15] 中=].但是你也应该每次都复制一份 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;
}
如果您想要修改您的个人 MySpecialClass
对象,并且不让更改反映在您复制的 HashMap
的 List
中,那么您将需要创建新的他们的副本也是。
不幸的是,这确实需要迭代。但是对于 Java 8 个流来说,这是非常微不足道的:
mapCopy = map.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> List.copyOf(e.getValue())))
序列化为 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());
对于特殊的 类,您可能需要 write a custom deserializer。
只需使用 Apache Commons Lang - SerializationUtils.clone();
像这样:
Map<String, List<MySpecialClass>> originalMap = new HashMap();
HashMap<String, List<MySpecialClass>> deepCopy = SerializationUtils.clone(new HashMap<>(originalMap));
还要确保 MySpecialClass 实现了 Serializable 接口。
public class MySpecialClass implements Serializable{}