Copying a HashMap in Java

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

myojbectsListA = new myojbectsList();
myojbectsListB = new myobjectsList();

then: Add some hashmap items to A (like2)

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 have original 2 still at end after last assingment 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.?

Answers


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.


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


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, anytime 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


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

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.


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.


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.


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


Need Your Help

How to sign in a user using Devise from a Rails console?

ruby-on-rails console devise

After loading the Rails console, how should I sign in a user?

Celery with Amazon SQS

amazon-web-services celery amazon-sqs kombu

I want to use Amazon SQS as broker backed of Celery. There’s the SQS transport implementation for Kombu, which Celery depends on. However there is not enough documentation for using it, so I cannot...