144

I am trying to keep a temporary container of a class that contains member :

HashMap<Integer,myObject> myobjectHashMap

A class called myobjectsList

Then I do

myobjectsListA = new myobjectsList();
myobjectsListB = new myobjectsList();

then: Add some hashmap items to A (like 2)

then:

myobjectListB = myobjectListA; //B has 2

then: Add hashmap items to A (like 4 more)

then: return A to the items stored in B

myobjectListA = myobjectListb;

But when I do this, B grows with A while I am adding hashmap items to A. A now has 6 items in it because B had 6.

I want A to still have the original 2 at the end after last assignment. In C++ I would use copy with objects, what is the java equivalent?

Added: OK I left something out explaining this. MyObjectsList does not contain the HashMap, it is derived from a class MyBaseOjbectsList which has the HashMap member and MyObjectsList extends MyBaseOjbectsList. Does this make a difference?

6
  • 1
    Can you post a SSCCE to give a better understanding of what you done so far?
    – assylias
    Commented Apr 9, 2012 at 20:22
  • 2
    Your objects should implement the Cloneable interface, otherwise assignments such as MyObjectB = MyObjectA simply tell the JVM that both variables point to the same location in memory. Not two distinct objects. Commented Apr 9, 2012 at 20:30
  • Btw, the overwhelming idiom (practically a law) is to capitalize class names. It will make your examples much more readable to those of us who use those things as quick cues while scanning example code. Commented Apr 9, 2012 at 20:38
  • 1
    to add on @KevinWelker it also helps the syntax highlighter highlight the class names Commented Apr 9, 2012 at 20:54
  • @Mike - Thanks but tried to do cloneable, it made them both grow when one grew. I don't want that.
    – user691305
    Commented Apr 10, 2012 at 12:35

11 Answers 11

270

If you want a copy of the HashMap you need to construct a new one with.

myobjectListB = new HashMap<Integer,myObject>(myobjectListA);

This will create a (shallow) copy of the map.

6
  • 5
    or if it is already created, use myObjectListB.addAll(myObjectListA) Commented Apr 9, 2012 at 20:36
  • Maybe i'm not understanding this but I don't need a copy of the map. I need a copy of the class that holds the map. ? There for myObjectListB has to be a class derived from MyojbectsList not a hashmap.
    – user691305
    Commented Apr 10, 2012 at 12:59
  • 10
    @Kevin Welker, addAll is for HashSet. putAll is for HashMap. Commented Feb 25, 2016 at 1:42
  • 5
    It didn't work. In my case the "new" variable were still pointing to the same object.
    – Thomio
    Commented Mar 18, 2018 at 22:49
  • 8
    @Thomio I mentioned that, that's what "shallow copy" means, If you need a deep copy to have to loop over the map and copy what you need. Commented Mar 18, 2018 at 22:55
19

You can also use

clone()

Method to copy all elements from one hashmap to another hashmap

Program for copy all elements from one hashmap to another

import java.util.HashMap;

public class CloneHashMap {    
     public static void main(String a[]) {    
        HashMap hashMap = new HashMap();    
        HashMap hashMap1 = new HashMap();    
        hashMap.put(1, "One");
        hashMap.put(2, "Two");
        hashMap.put(3, "Three");
        System.out.println("Original HashMap : " + hashMap);
        hashMap1 = (HashMap) hashMap.clone();
        System.out.println("Copied HashMap : " + hashMap1);    
    }    
}

source : http://www.tutorialdata.com/examples/java/collection-framework/hashmap/copy-all-elements-from-one-hashmap-to-another

5
  • 14
    You can, but you probably shouldn't because Cloneable is essentially broken, per Joshua Bloch's Effective Java #11. Commented Jun 14, 2013 at 4:18
  • 14
    also, note that clone() returns a shallow copy.
    – Vinay W
    Commented Sep 16, 2013 at 10:13
  • 3
    What does shallow even mean? If it does not copy the map exactly (with keys/values intact), why bother? Might as well create a new map, right?
    – Azurespot
    Commented Oct 26, 2016 at 23:17
  • 3
    @Azurespot shallow means it won't copy any nested objects and their nested objects...
    – nofunatall
    Commented Mar 23, 2018 at 18:11
  • 2
    If you look at the source, all clone() does is create a new HashMap and putAll everything into it. It's completely pointless.
    – Ariel
    Commented Jul 23, 2018 at 16:36
14

The difference is that in C++ your object is on the stack, whereas in Java, your object is in the heap. If A and B are Objects, any time in Java you do:

B = A

A and B point to the same object, so anything you do to A you do to B and vice versa.

Use new HashMap() if you want two different objects.

And you can use Map.putAll(...) to copy data between two Maps.

2
  • Is that the same as saying Java is all by reference and C++ is sometimes reference and sometimes value? But I don't want a HashMap, I wan't a duplicate copy of the class I can use as temp storage.
    – user691305
    Commented Apr 10, 2012 at 13:02
  • I don't have access to the HashMap in the base class. Again, I have to work with classes derived from the base. I cannot access the HashMap in it.
    – user691305
    Commented Apr 10, 2012 at 13:24
10

Since Java 10 it is possible to use

Map.copyOf

for creating a shallow copy, which is also immutable. (Here is its Javadoc). For a deep copy, as mentioned in this answer, you need some kind of value mapper to make a safe copy of values. You don't need to copy keys though, since they must be immutable.

6

There is a small (HUGE) understatement here. If you want to copy a HashMap with nested structures, HashMap.putAll() will copy by reference, because it doesn't know how to exactly copy your object. For example:

import java.util.*;
class Playground {
    public static void main(String[ ] args) {
        Map<Integer, Map<Integer,List<Float>>> dataA = new HashMap<>();
        Map<Integer, Map<Integer,List<Float>>> dataB = new HashMap<>();

        dataA.put(1, new HashMap<>());
        dataB.putAll(dataA);

        assert(dataB.get(1).size() == 0);

        dataA.get(1).put(2, new ArrayList<>());

        if (dataB.get(1).size() == 1) { // true
            System.out.println(
                "Sorry object reference was copied - not the values");
        }
    }
}

So basically you will need to copy the fields yourself like here

List <Float> aX = new ArrayList<>(accelerometerReadingsX);
List <Float> aY = new ArrayList<>(accelerometerReadingsY);

List <Float> gX = new ArrayList<>(gyroscopeReadingsX);
List <Float> gY = new ArrayList<>(gyroscopeReadingsY);

Map<Integer, Map<Integer, Float>> readings = new HashMap<>();

Map<Integer,List<Float>> accelerometerReadings = new HashMap<>();
accelerometerReadings.put(X_axis, aX);
accelerometerReadings.put(Y_axis, aY);
readings.put(Sensor.TYPE_ACCELEROMETER, accelerometerReadings);

Map<Integer,List<Float>> gyroscopeReadings = new HashMap<>();
gyroscopeReadings.put(X_axis, gX);
gyroscopeReadings.put(Y_axis, gY);
readings.put(Sensor.TYPE_GYROSCOPE, gyroscopeReadings);
6

If we want to copy an object in Java, there are two possibilities that we need to consider: a shallow copy and a deep copy.

The shallow copy is the approach when we only copy field values. Therefore, the copy might be dependent on the original object. In the deep copy approach, we make sure that all the objects in the tree are deeply copied, so the copy is not dependent on any earlier existing object that might ever change.

This question is the perfect definition for the application of the deep copy approach.

First, if you have a simple HashMap<Integer, List<T>> map then we just create a workaround like this. Creating a new instance of the List<T>.

public static <T> HashMap<Integer, List<T>> deepCopyWorkAround(HashMap<Integer, List<T>> original)
{
    HashMap<Integer, List<T>> copy = new HashMap<>();
    for (Map.Entry<Integer, List<T>> entry : original.entrySet()) {
        copy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
    }
    return copy;
}

This one uses Stream.collect() method to create the clone map, but uses the same idea as the previous method.

public static <T> Map<Integer, List<T>> deepCopyStreamWorkAround(Map<Integer, List<T>> original)
{
    return original
            .entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey, valueMapper -> new ArrayList<>(valueMapper.getValue())));
}   

But, if the instances inside T are also mutable objects we have a big problem. In this case a real deep copy is an alternative that solves this problem. Its advantage is that at least each mutable object in the object graph is recursively copied. Since the copy is not dependent on any mutable object that was created earlier, it won’t get modified by accident like we saw with the shallow copy.

To solve that this deep copy implementations will do the work.

public class DeepClone
{
    public static void main(String[] args)
    {
        Map<Long, Item> itemMap = Stream.of(
                entry(0L, new Item(2558584)),
                entry(1L, new Item(254243232)),
                entry(2L, new Item(986786)),
                entry(3L, new Item(672542)),
                entry(4L, new Item(4846)),
                entry(5L, new Item(76867467)),
                entry(6L, new Item(986786)),
                entry(7L, new Item(7969768)),
                entry(8L, new Item(68868486)),
                entry(9L, new Item(923)),
                entry(10L, new Item(986786)),
                entry(11L, new Item(549768)),
                entry(12L, new Item(796168)),
                entry(13L, new Item(868421)),
                entry(14L, new Item(923)),
                entry(15L, new Item(986786)),
                entry(16L, new Item(549768)),
                entry(17L, new Item(4846)),
                entry(18L, new Item(4846)),
                entry(19L, new Item(76867467)),
                entry(20L, new Item(986786)),
                entry(21L, new Item(7969768)),
                entry(22L, new Item(923)),
                entry(23L, new Item(4846)),
                entry(24L, new Item(986786)),
                entry(25L, new Item(549768))
        ).collect(entriesToMap());


        Map<Long, Item> clone = DeepClone.deepClone(itemMap);
        clone.remove(1L);
        clone.remove(2L);

        System.out.println(itemMap);
        System.out.println(clone);
    }

    private DeepClone() {}

    public static <T> T deepClone(final T input)
    {
        if (input == null) return null;

        if (input instanceof Map<?, ?>) {
            return (T) deepCloneMap((Map<?, ?>) input);
        } else if (input instanceof Collection<?>) {
            return (T) deepCloneCollection((Collection<?>) input);
        } else if (input instanceof Object[]) {
            return (T) deepCloneObjectArray((Object[]) input);
        } else if (input.getClass().isArray()) {
            return (T) clonePrimitiveArray((Object) input);
        }

        return input;
    }

    private static Object clonePrimitiveArray(final Object input)
    {
        final int length = Array.getLength(input);
        final Object output = Array.newInstance(input.getClass().getComponentType(), length);
        System.arraycopy(input, 0, output, 0, length);
        return output;
    }

    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;
        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 <K, V> Map<K, V> deepCloneMap(final Map<K, V> map)
    {
        Map<K, V> clone;
        if (map instanceof LinkedHashMap<?, ?>) {
            clone = new LinkedHashMap<>();
        } else if (map instanceof TreeMap<?, ?>) {
            clone = new TreeMap<>();
        } else {
            clone = new HashMap<>();
        }

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

        return clone;
    }
}
4

In Java, when you write:

Object objectA = new Object();
Object objectB = objectA;

objectA and objectB are the same and point to the same reference. Changing one will change the other. So if you change the state of objectA (not its reference) objectB will reflect that change too.

However, if you write:

objectA = new Object()

Then objectB is still pointing to the first object you created (original objectA) while objectA is now pointing to a new Object.

6
  • that explains the problem, whats the solution? Or is this a limitation of Java with no work around?
    – user691305
    Commented Apr 10, 2012 at 13:23
  • 1
    That's not a limitation, it is the way it works. If you want 2 different objects, you create 2 objects - if you only create one object, then all the variables that point to that object are equal.
    – assylias
    Commented Apr 10, 2012 at 13:25
  • I suggest you create a new question with all the relevant code (ideally a SSCCE) and explain precisely what you are trying to achieve.
    – assylias
    Commented Apr 10, 2012 at 13:26
  • creating a new object and wiping out the original values is not the goal. The goal is to keep the original values and use only them again later in a copy that received more new values.
    – user691305
    Commented Apr 10, 2012 at 14:55
  • Well it really depends on the object. If it does not provide a way to create a new copy object, then it is complicated because the object has not been designed to be copied (maybe on purpose - but you can still do it using reflection). If the object does implement that feature (see for example the answer with the copy constructor of HashMap) then you just use the provided method.
    – assylias
    Commented Apr 10, 2012 at 15:13
2

Java Copying a HashMap

Java supports shallow(not deep) copy concept

You can archive it using:

  • constructor
  • clone()
  • putAll()
0
1

Since this question is still unanswered and I had a similar problem, I will try to answer this. The problem (as others already mentioned) is that you just copy references to the same object and thus a modify on the copy will also modify the origin object. So what you have to to is to copy the object (your map value) itself. The far easiest way to do so is to make all your objects implementing the serializeable interface. Then serialize and deserialize your map to get a real copy. You can do this by yourself or use the apache commons SerializationUtils#clone() which you can find here: https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/SerializationUtils.html But be aware this is the simplest approach but it is an expensive task to serialize and deserialize a lot of objects.

0

What you assign one object to another, all you're doing is copying the reference to the object, not the contents of it. What you need to do is take your object B and manually copy the contents of object A into it.

If you do this often, you might consider implementing a clone() method on the class that will create a new object of the same type, and copy all of it's contents into the new object.

2
  • Clone did the same thing it just seemed to pass the reference.
    – user691305
    Commented Apr 10, 2012 at 13:06
  • Also, when one increases its HashMap count, the copy does too, don't want that. I want idependent containers(in this case classes) of the same type.
    – user691305
    Commented Apr 10, 2012 at 13:34
0

Since the OP has mentioned he does not have access to the base class inside of which exists a HashMap - I am afraid there are very few options available.

One (painfully slow and resource intensive) way of performing a deep copy of an object in Java is to abuse the 'Serializable' interface which many classes either intentionally - or unintentionally extend - and then utilise this to serialise your class to ByteStream. Upon de-serialisation you will have a deep copy of the object in question.

A guide for this can be found here: https://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html

Not the answer you're looking for? Browse other questions tagged or ask your own question.