将Hashmap分配给Hashmap

我有一个哈希地图,我想复制其他用途。 但每当我复制并重复使用它时,它也会改变原来的。 这是为什么?

do { Map<Integer, Map> map1 = originalMap; //at the second iteration originalMap is the same as map1 of the last iteration, //eventhough the change was nog accepted; //do something with map1 (change value); if(change is accepted) { originalMap = map1; } } while(iteration < 10); 

提前致谢

  public static Map<Integer, Map> deepCopy(Map<Integer, Map> original) { Map<Integer, Map> copy = new HashMap<Integer, Map>(); for (Map.Entry<Integer, Map> entry : original.entrySet()) { copy.put(entry.getKey(), deepCopy2(entry.getValue())); } return copy; } public static Map deepCopy2(Map original) { Map copy = new HashMap(); for (Map.Entry entry : original.entrySet()) { copy.put(entry.getKey(), entry.getValue()); } return copy; } 

你所做的不是创建地图的副本,而是创建地图的副本。 当两个引用指向同一个对象时,对一个引用的更改将反映在另一个引用中。

解决方案1:如果这是从某种简单类型到另一种类型的Map,您可以这样做:

 Map map1 = new HashMap(original); 

这称为复制构造函数 。 几乎所有标准的Collection和Map实现都有一个,它通常是克隆简单结构的最简单方法。 只要SomeTypeOtherType是不可变的 (例如Integer和其他Number类型, BooleanString ,但不是集合,日期,地图,数组等),这将正常工作。

如果没有,正如其他答复者和评论者指出的那样,您还需要复制地图值。

解决方案2:这是一个应该安全的快速且脏的版本:

 Map> original=new HashMap>(); Map> copy = new HashMap>(); for(Entry> entry : original.entrySet()){ copy.put(entry.getKey(), new HashMap(entry.getValue())); } 

但实际上,我喜欢Hunter提供深度复制方法的想法。 所以这里的解决方案3:我自己的版本使用通用参数:

 public static  Map> deepCopy( Map> original){ Map> copy = new HashMap>(); for(Entry> entry : original.entrySet()){ copy.put(entry.getKey(), new HashMap(entry.getValue())); } return copy; } 

你可以这样称呼它:

 Map> original=new HashMap>(); // do stuff here Map> copy = deepCopy(original); 

更新

我已经攻击了一个为地图,集合和数组执行深度克隆的类(原始和其他)。 用法:

 Something clone = DeepClone.deepClone(original); 

这里是:

 public final class DeepClone { private DeepClone(){} public static  X deepClone(final X input) { if (input == null) { return input; } else if (input instanceof Map) { return (X) deepCloneMap((Map) input); } else if (input instanceof Collection) { return (X) deepCloneCollection((Collection) input); } else if (input instanceof Object[]) { return (X) deepCloneObjectArray((Object[]) input); } else if (input.getClass().isArray()) { return (X) clonePrimitiveArray((Object) input); } return input; } private static Object clonePrimitiveArray(final Object input) { final int length = Array.getLength(input); final Object copy = Array.newInstance(input.getClass().getComponentType(), length); // deep clone not necessary, primitives are immutable System.arraycopy(input, 0, copy, 0, length); return copy; } private static  E[] deepCloneObjectArray(final E[] input) { final E[] clone = (E[]) Array.newInstance(input.getClass().getComponentType(), input.length); for (int i = 0; i < input.length; i++) { clone[i] = deepClone(input[i]); } return clone; } private static  Collection deepCloneCollection(final Collection input) { Collection clone; // this is of course far from comprehensive. extend this as needed if (input instanceof LinkedList) { clone = new LinkedList(); } else if (input instanceof SortedSet) { clone = new TreeSet(); } else if (input instanceof Set) { clone = new HashSet(); } else { clone = new ArrayList(); } for (E item : input) { clone.add(deepClone(item)); } return clone; } private static  Map deepCloneMap(final Map map) { Map clone; // this is of course far from comprehensive. extend this as needed if (map instanceof LinkedHashMap) { clone = new LinkedHashMap(); } else if (map instanceof TreeMap) { clone = new TreeMap(); } else { clone = new HashMap(); } for (Entry entry : map.entrySet()) { clone.put(deepClone(entry.getKey()), deepClone(entry.getValue())); } return clone; } } 

通过做这个:

 Map> copy = originalMap; 

…你没有复制地图,只是创建了一个引用完全相同的地图的新变量,显然你使用这个变量所做的更改将反映在原始地图中 – 它们指向同一个对象记忆。 使用接收另一个地图作为参数的构造函数更好地复制原始地图:

 Map> copy; copy = new HashMap>(originalMap); 

上面的代码将创建原始地图的浅表副本 ,这意味着:如果更改一个地图内的元素 ,则更改将反映在另一个地图中,但您可以自由地添加/删除地图中的元素和其他不会受到影响。 如果这还不够好,则需要在复制时对地图中的元素执行深层复制

一个简单而直接的解决方案是循环遍历Map中的值并将它们复制到Map中:

 Map> map1; //iterate over the map copying values into new map for(Map.Entry entry : originalMap.entrySet()) { map1.put(entry.getKey(), new HashMap(entry.getValue())); } 

更好的解决方案是将其包装在一个方法中:

 public static  Map> deepCopy(Map> original) { Map> copy; //iterate over the map copying values into new map for(Map.Entry> entry : original.entrySet()) { copy.put(entry.getKey(), new HashMap(entry.getValue())); } return copy; } 

在您的代码中, originalMap只是对map1的引用。 现在,他们都指向相同的键和值。 请记住,这是Java,其中对象引用上的’=’只是一个引用赋值(不是深拷贝或浅拷贝)。

Java集合通常通过cloneputAll支持某种forms的浅拷贝。 在地图的情况下,假设map1map2的类型为HashMap ,如果您希望一个地图是另一个地图的浅层副本(意思是一个不同的HashMap对象,但具有共享键和值),则执行此操作:

 HashMap map1(); HashMap map2(); map2.put(x1,v1); // map2 = {{x1,v1}} map1.put(x2,v2); // map1 = {{x2,v2}} map1 = map2.clone(); // map1 = {{x1,v1}}, with x2 and v2 gone map2.clear(); map2.put(x3,v3); // map2 = {{x3,v3}} map2.put(x4,v4); // map2 = {{x3,v3},{x4,v4}} map1.put(x4,v5); // map1 = {{x1,v1}, {x4,v5}} // add all of map2 into map1, replacing any mappings with shared keys map1.putAll(map2); // map1 = {{x1,v1},{x3,v3},{x4,v4}}, notice how v5 is gone 

在离别的思想中,你需要养成查看Java API的习惯。 它会帮助你很多。

http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html

这可能会有点晚,但另一个简单的解决方案是将地图序列化为输出流并将其反序列化为新的地图对象。 这也是打破单身人士模式的最简单方法之一。