Assigning Hashmap to Hashmap

后端 未结 5 1283
轻奢々
轻奢々 2020-12-14 10:13

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 {
                    


        
5条回答
  •  庸人自扰
    2020-12-14 10:41

    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:

    Map map1 = new HashMap(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. This will work fine as long as SomeType and OtherType are immutable (e.g. Integer and other Number types, Boolean, String, but not Collections, Dates, Maps, Arrays etc.)

    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:

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

    But actually, I like Hunter's idea of providing a deep copy method. So here's Solution 3: my own version using generic parameters:

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

    You can call it like this:

    Map> original=new HashMap>();
    // do stuff here
    Map> 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 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;
        }
    }
    

提交回复
热议问题