Mangat Rai Modi
Mangat Rai Modi

Reputation: 5706

Java HashMap: A Bug in JVM or I am doing wrong?

In the code below:-

  1. Create the HashMap and add some elements.
  2. Create second HashMap taking the mapping of first.
  3. Modify the second HashMap.
  4. First HashMap is modified along with?

    public static void test(){
        HashMap<Integer, ArrayList<Integer>> testData = new HashMap<Integer, ArrayList<Integer>> ();
        testData.put(1, new ArrayList<Integer>(Arrays.asList(777)));
        System.out.println(testData);
        HashMap<Integer,ArrayList<Integer>> testData1 = new HashMap<Integer, ArrayList<Integer>> (testData);
        testData1.get(1).add(888);
        System.out.println(testData);
    }
    

Output:

{1=[777]}
{1=[777, 888]}

Try it here: Code on Ideone.com

I expected both testData and testData1 to be independent of each other, but it seems like both of them refer to same object? Is it intended in Java? Am I doing something wrong?

Upvotes: 1

Views: 163

Answers (2)

Panther
Panther

Reputation: 3339

All the collections in java hold refrences to object. So, while you are modifying list from second map, it is modifying the same object of list

Upvotes: 0

janos
janos

Reputation: 124646

You're making a shallow copy of the original HashMap: the list references are copied, then their items.

You need to do a deep copy yourself:

    HashMap<Integer, List<Integer>> testData = new HashMap<>();
    testData.put(1, new ArrayList<>(Arrays.asList(777)));

    HashMap<Integer, List<Integer>> testData = new HashMap<>();
    testData.put(1, Arrays.asList(777));

    HashMap<Integer, List<Integer>> testData2 = new HashMap<>();
    for (Map.Entry<Integer, List<Integer>> entry : testData.entrySet()) {
        testData2.put(entry.getKey(), new ArrayList<>(entry.getValue()));
    }
    testData2.get(1).add(888);
    System.out.println(testData);
    System.out.println(testData2);

This prints:

{1=[777]}
{1=[777, 888]}

As @jon-kiparsky explained nicely in a comment:

This may be obvious, but just for completeness: since a HashMap stores objects, not primitives, your maps store references to objects. This is why you need to think in terms of deep and shallow copies.

And as a side note, I also improved your example code:

  • Use interface types in declarations instead of implementation types
  • No need to wrap Arrays.asList(...) inside a new ArrayList<>(...)
  • Use the diamond operator <> in Java 7 (and consequently use Java 7 or later as older versions are no longer supported)

Upvotes: 4

Related Questions