简体   繁体   English

将Hashmap分配给Hashmap

[英]Assigning Hashmap to Hashmap

I have a hashmap which I want to copy for other use. 我有一个哈希地图,我想复制其他用途。 But whenever I copy it and reuse it, it also changes the original one. 但每当我复制并重复使用它时,它也会改变原来的。 Why is that? 这是为什么?

    do {
            Map<Integer, Map<String, Object>> 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);

Thanks in advance 提前致谢

    public static <Integer,String, Schedule>Map<Integer, Map<String, Schedule>> deepCopy(Map<Integer, Map<String, Schedule>> original) {
    Map<Integer, Map<String, Schedule>> copy = new HashMap<Integer, Map<String, Schedule>>();

    for (Map.Entry<Integer, Map<String, Schedule>> entry : original.entrySet()) {
        copy.put(entry.getKey(), deepCopy2(entry.getValue()));
    }
    return copy;
}

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

    return copy;
}

What you did was not to create a copy of the map, but of the reference to it. 你所做的不是创建地图的副本,而是创建地图的副本。 when two references point to the same object, changes to one will reflect in the other. 当两个引用指向同一个对象时,对一个引用的更改将反映在另一个引用中。

Solution 1: If this was a Map from some simple type to another, you would do this instead: 解决方案1:如果这是一个从简单类型到另一个类型的Map,那么您可以这样做:

Map<SomeType, OtherType> map1 = new HashMap<SomeType, OtherType>(original); 

This is called a Copy Constructor . 这称为复制构造函数 Almost All standard Collection and Map implementations have one, and it's usually the simplest way to clone a simple structure. 几乎所有标准的Collection和Map实现都有一个,它通常是克隆简单结构的最简单方法。 This will work fine as long as SomeType and OtherType are immutable (eg Integer and other Number types, Boolean , String , but not Collections, Dates, Maps, Arrays etc.) 只要SomeTypeOtherType不可变的 (例如Integer和其他Number类型, BooleanString ,但不是集合,日期,地图,数组等),这将正常工作。

If not, as other answerers and commenters have pointed out, you also need to copy the map values. 如果没有,正如其他答复者和评论者指出的那样,您还需要复制地图值。

Solution 2: Here's a quick and dirty version that should be safe: 解决方案2:这是一个安全的快速和脏的版本:

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

But actually, I like Hunter's idea of providing a deep copy method. 但实际上,我喜欢Hunter提供深度复制方法的想法。 So here's Solution 3: my own version using generic parameters: 所以这里的解决方案3:我自己的版本使用通用参数:

public static <K1, K2, V> Map<K1, Map<K2, V>> deepCopy(
    Map<K1, Map<K2, V>> original){

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

You can call it like this: 你可以这样称呼它:

Map<Integer, Map<String, Object>> original=new HashMap<Integer, Map<String,Object>>();
// do stuff here
Map<Integer, Map<String, Object>> copy = deepCopy(original);

Update 更新

I've hacked together a class that performs deep cloning for Maps, Collections and Arrays (primitive and otherwise). 我已经攻击了一个为地图,集合和数组(原始和其他)执行深度克隆的类。 Usage: 用法:

Something clone = DeepClone.deepClone(original);

Here it is: 这里是:

public final class DeepClone {

    private DeepClone(){}

    public static <X> 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> 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 <E> Collection<E> deepCloneCollection(final Collection<E> input) {
        Collection<E> clone;
        // this is of course far from comprehensive. extend this as needed
        if (input instanceof LinkedList<?>) {
            clone = new LinkedList<E>();
        } else if (input instanceof SortedSet<?>) {
            clone = new TreeSet<E>();
        } else if (input instanceof Set) {
            clone = new HashSet<E>();
        } else {
            clone = new ArrayList<E>();
        }

        for (E item : input) {
            clone.add(deepClone(item));
        }

        return clone;
    }

    private static <K, V> Map<K, V> deepCloneMap(final Map<K, V> map) {
        Map<K, V> clone;
        // this is of course far from comprehensive. extend this as needed
        if (map instanceof LinkedHashMap<?, ?>) {
            clone = new LinkedHashMap<K, V>();
        } else if (map instanceof TreeMap<?, ?>) {
            clone = new TreeMap<K, V>();
        } else {
            clone = new HashMap<K, V>();
        }

        for (Entry<K, V> entry : map.entrySet()) {
            clone.put(deepClone(entry.getKey()), deepClone(entry.getValue()));
        }

        return clone;
    }
}

By doing this: 通过做这个:

Map<Integer, Map<String, Object>> copy = originalMap;

... you're not copying the map, only creating a new variable which refers to the exact same map, and clearly the changes you make using this variable will be reflected in the original map - they're pointing to the same object in memory. ...你没有复制地图,只创建一个引用完全相同的地图的新变量,显然你使用这个变量所做的更改将反映在原始地图中 - 它们指向同一个对象记忆。 Better copy the original map using the constructor that receives another map as a parameter: 最好使用接收另一个地图作为参数的构造函数复制原始地图:

Map<Integer, Map<String, Object>> copy;
copy = new HashMap<Integer, Map<String, Object>>(originalMap);

The above code will create a shallow copy of the original map, meaning: if you change the value of the elements inside one map, the changes will be reflected in the other, but you can add/remove freely the elements from either map and the other won't be affected. 上面的代码将创建原始地图的浅表副本 ,这意味着:如果更改一个地图中的元素 ,则更改将反映在另一个地图中,但您可以自由地添加/删除地图中的元素和其他不会受到影响。 If that's not good enough, you'll need to perform a deep copy of the elements in the map at the time of copying it. 如果这还不够好,您需要在复制时对地图中的元素执行深层复制

A simple and straightforward solution would be to just loop over the values in the Map and copy them into a Map: 一个简单而直接的解决方案是循环遍历Map中的值并将它们复制到Map中:

Map<Integer, Map<String, Object>> map1;

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

A better solution would be to wrap this in a method: 更好的解决方案是将其包装在一个方法中:

public static <K,J,V> Map<K, Map<J, V>> deepCopy(Map<K, Map<J, V>> original)
{
    Map<K, Map<J, V>> copy;

    //iterate over the map copying values into new map
    for(Map.Entry<K, Map<J, V>> entry : original.entrySet())
    {
       copy.put(entry.getKey(), new HashMap<J, V>(entry.getValue()));
    }

    return copy;
}

In your code, originalMap is simply a reference to map1 . 在您的代码中, originalMap只是对map1的引用。 Now, they both point to the same keys and values. 现在,他们都指向相同的键和值。 Remember, this is Java where '=' on object references is simply an reference assignment (not a deep or shallow copy). 请记住,这是Java,对象引用上的'='只是一个引用赋值(不是深拷贝或浅拷贝)。

Java collections typically support some form of shallow copying via clone or putAll . Java集合通常通过cloneputAll支持某种形式的浅拷贝。 In the case of maps, assuming map1 and map2 are of type HashMap<KeyType,ValueType> , if you want one map to be a shallow copy of another (meaning, a distinct HashMap object but with shared keys and values), you do this: 在地图的情况下,假设map1map2的类型为HashMap<KeyType,ValueType> ,如果您希望一个地图是另一个地图的浅层副本(意思是一个不同的HashMap对象,但是具有共享键和值),那么你这样做:

HashMap<KeyType,ValueType> map1();
HashMap<KeyType,ValueType> 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

On a parting thought, you need to make it a habit of looking at the Java API. 在离别的思想中,你需要养成查看Java API的习惯。 It will help you a lot. 它会帮助你很多。

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

This might be coming a bit late, but another simple solution will be to Serialize the map to an output Stream and de-serialize it to a new Map Object. 这可能会有点晚,但另一个简单的解决方案是将地图序列化为输出流并将其反序列化为新的地图对象。 Thats also one of the easiest ways to break the singleton pattern. 这也是打破单身人士模式的最简单方法之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM