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;
}
Use Casesis a perfect candidate for a nested HashMap. In general, whenever we need to embed one object in another object, we can use them.
put() method of HashMap is used to insert a mapping into a map. This means we can insert a specific key and the value it is mapping to into a particular map. If an existing key is passed then the previous value gets replaced by the new value. If a new pair is passed, then the pair gets inserted as a whole.
Java HashMap. Java HashMap class implements the Map interface which allows us to store key and value pair, where keys should be unique. If you try to insert the duplicate key, it will replace the element of the corresponding key. It is easy to perform operations using the key index like updation, deletion, etc.
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<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.
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<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. So here's Solution 3: my own version using generic parameters:
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With