簡體   English   中英

將Hashmap分配給Hashmap

[英]Assigning Hashmap to Hashmap

我有一個哈希地圖,我想復制其他用途。 但每當我復制並重復使用它時,它也會改變原來的。 這是為什么?

    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);

提前致謝

    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;
}

你所做的不是創建地圖的副本,而是創建地圖的副本。 當兩個引用指向同一個對象時,對一個引用的更改將反映在另一個引用中。

解決方案1:如果這是一個從簡單類型到另一個類型的Map,那么您可以這樣做:

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

這稱為復制構造函數 幾乎所有標准的Collection和Map實現都有一個,它通常是克隆簡單結構的最簡單方法。 只要SomeTypeOtherType不可變的 (例如Integer和其他Number類型, BooleanString ,但不是集合,日期,地圖,數組等),這將正常工作。

如果沒有,正如其他答復者和評論者指出的那樣,您還需要復制地圖值。

解決方案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()));
}

但實際上,我喜歡Hunter提供深度復制方法的想法。 所以這里的解決方案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;
}

你可以這樣稱呼它:

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

更新

我已經攻擊了一個為地圖,集合和數組(原始和其他)執行深度克隆的類。 用法:

Something clone = DeepClone.deepClone(original);

這里是:

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;
    }
}

通過做這個:

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

...你沒有復制地圖,只創建一個引用完全相同的地圖的新變量,顯然你使用這個變量所做的更改將反映在原始地圖中 - 它們指向同一個對象記憶。 最好使用接收另一個地圖作為參數的構造函數復制原始地圖:

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

上面的代碼將創建原始地圖的淺表副本 ,這意味着:如果更改一個地圖中的元素 ,則更改將反映在另一個地圖中,但您可以自由地添加/刪除地圖中的元素和其他不會受到影響。 如果這還不夠好,您需要在復制時對地圖中的元素執行深層復制

一個簡單而直接的解決方案是循環遍歷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()));
}

更好的解決方案是將其包裝在一個方法中:

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;
}

在您的代碼中, originalMap只是對map1的引用。 現在,他們都指向相同的鍵和值。 請記住,這是Java,對象引用上的'='只是一個引用賦值(不是深拷貝或淺拷貝)。

Java集合通常通過cloneputAll支持某種形式的淺拷貝。 在地圖的情況下,假設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

在離別的思想中,你需要養成查看Java API的習慣。 它會幫助你很多。

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

這可能會有點晚,但另一個簡單的解決方案是將地圖序列化為輸出流並將其反序列化為新的地圖對象。 這也是打破單身人士模式的最簡單方法之一。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM