2012-07-02 10 views
13

पर असाइन करना मेरे पास एक हैशैप है जिसे मैं अन्य उपयोग के लिए कॉपी करना चाहता हूं। लेकिन जब भी मैं इसे कॉपी करता हूं और इसका पुन: उपयोग करता हूं, यह मूल को भी बदल देता है। वह क्यों है?हैशमैप को हैशमैप

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

क्योंकि यह 'हैश मैप' की एक प्रति नहीं है, यह वास्तविक 'हैश मैप' के लिए _reference_ है, जिसका अर्थ है कि किसी भी बदलाव से दूसरे को प्रभावित किया जाएगा। आपको 'हैश मैप' –

उत्तर

47

आप क्या धन्यवाद था नक्शे की एक प्रति बनाने के लिए नहीं है, लेकिन यह करने के लिए संदर्भ की। जब दो संदर्भ एक ही वस्तु को इंगित करते हैं, तो एक में परिवर्तन दूसरे में दिखाई देगा।

समाधान 1: यदि यह एक और के लिए कुछ सरल प्रकार से एक नक्शा था, तो आप इस बजाय करना होगा:

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

यह एक Copy Constructor कहा जाता है। लगभग सभी मानक संग्रह और मानचित्र कार्यान्वयन में एक है, और यह आमतौर पर एक साधारण संरचना को क्लोन करने का सबसे आसान तरीका है। यह रूप में लंबे समय के रूप में SomeType और OtherType हैं immutable तरीके से कार्य करेंगे (Integer जैसे और अन्य Number प्रकार, Boolean, String, लेकिन नहीं संग्रह, तिथियाँ, मैप्स, सारणी, आदि)

यदि नहीं

, अन्य answerers और टिप्पणीकर्ताओं है के रूप में इंगित किया गया है, आपको मानचित्र मानों की प्रतिलिपि बनाने की भी आवश्यकता है।

समाधान 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())); 
} 

लेकिन वास्तव में, मैं एक गहरी प्रतिलिपि विधि प्रदान करने का हंटर के विचार की तरह। तो यहाँ समाधान 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); 

अद्यतन

मैं एक साथ एक काट दिया गया है कक्षा जो मानचित्र, संग्रह और Arrays (आदिम और अन्यथा) के लिए गहरी क्लोनिंग करता है। उपयोग:

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

की _deep_ प्रतिलिपि करने की आवश्यकता है, यह सोचकर कि क्लोन() हैश मैप की प्रतिलिपि बनाने का एक अच्छा तरीका होगा? –

+0

@ लुइस ने किया। एलेक्सी, मुझे संदेह है कि क्लोन आवश्यकतानुसार गहरी प्रतिलिपि करेगा। –

+2

'क्लोन()' लगभग कभी भी एक अच्छा विचार नहीं है (प्रभावी जावा आइटम 11), लेकिन यह विशेष रूप से इस मामले में नौकरी नहीं करने जा रहा है। –

3

ऐसा करने से:

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

... आप कर रहे हैं नहीं मानचित्र को कॉपी, केवल एक नया वेरिएबल बनाने जो सटीक उसी मानचित्र को संदर्भित करता है, और स्पष्ट रूप से आपके द्वारा इस चर का उपयोग करके किए गए परिवर्तन मूल मानचित्र में दिखाई देंगे - वे स्मृति में एक ही ऑब्जेक्ट को इंगित कर रहे हैं।बेहतर मूल नक्शा नकल constructor कि एक पैरामीटर के रूप में एक और नक्शा प्राप्त करता है का उपयोग करते हुए:,

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

ऊपर कोड मूल नक्शे की एक उथले प्रतिलिपि पैदा करेगा जिसका अर्थ है: यदि आप मूल्य तत्वों की बदल एक मानचित्र के अंदर, परिवर्तन दूसरे में दिखाई देंगे, लेकिन आप किसी भी मानचित्र से तत्वों को स्वतंत्र रूप से जोड़/निकाल सकते हैं और दूसरा प्रभावित नहीं होगा। यदि यह पर्याप्त नहीं है, तो आपको इसे कॉपी करने के समय मानचित्र में तत्वों के गहरी प्रति निष्पादित करने की आवश्यकता होगी।

2

एक सरल और सीधा समाधान मानचित्र में मूल्यों पर सिर्फ पाश करने के लिए हो सकता है और एक मानचित्र में उन्हें नकल होगा:

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

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

एक बेहतर समाधान के लिए एक विधि में इस रैप करने के लिए किया जाएगा

+0

मैं मानता हूं कि यह विधि एक बेहतर विचार होगा (इसके लिए +1), लेकिन मैं इसे पुन: प्रयोज्य बनाने के लिए जेनेरिक वाइल्डकार्ड जोड़ूंगा (और इसे स्थैतिक बना दूंगा) –

+0

संपादन सुरक्षा के लिए संपादन प्रगति पर था। यह स्थिर, अच्छी बिंदु –

+0

भी होनी चाहिए, इसलिए अब हमारे दोनों के पास हमारे उत्तर में एक ही विधि है :-) –

0

अपने कोड में, originalMap बस map1 का संदर्भ है। अब, वे दोनों एक ही कुंजी और मूल्यों को इंगित करते हैं। याद रखें, यह जावा है जहां ऑब्जेक्ट संदर्भों पर '=' बस एक संदर्भ असाइनमेंट है (गहरी या उथली प्रति नहीं)।

जावा संग्रह आमतौर पर clone या putAll के माध्यम से उथले प्रतिलिपि के कुछ रूपों का समर्थन करते हैं। नक्शे के मामले में, map1 और map2 संभालने में, प्रकार 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 

एक अलग विचार पर, आपको इसे जावा एपीआई देखने की आदत बनाने की आवश्यकता है। यह आपको बहुत मदद करेगा।

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

0

इसमें कुछ समय आ रहा है हो सकता है देर से, लेकिन एक और सरल समाधान एक आउटपुट स्ट्रीम करने के लिए नक्शे को क्रमानुसार करने और यह एक नया मानचित्र वस्तु को डी-क्रमानुसार किया जाएगा। सिंगलटन पैटर्न को तोड़ने के सबसे आसान तरीकों में से एक है।

+1

हाँ मैंने इसे देखा, लेकिन पहले के चरण में संदर्भ काफी आसान था। तो गहरी प्रतिलिपि के साथ कॉपी करना बहुत अच्छा है, लेकिन अभी यह काम नहीं कर रहा है –

संबंधित मुद्दे