2

I am having difficulties understanding the HashMap when using Object as a type.

Here I create two objects, a string and an integer, which I assign a value to. I then add these object to a HashMap. Then the values of the string and integer objects are changed. But when trying to refer to them using the HashMap.get() it shows the original values.

I assume that somehow when putting the values on the HashMap create a new unchanged object is created in the HashMap instance instead of linking the underlying original object?

Here is the code:

import java.util.HashMap;
import java.util.Map;
public class Test1 {
    //Create objects
    static int integ=1;
    static String strng="Hi";
    //Create HashMap
    static Map<String, Object> objMap = new HashMap(); //Map of shipments
    public static void main(String[] args) {
        //Insert objects in HashMap
        objMap.put("integer", integ);
        objMap.put("string", strng);
        //Check the values
        System.out.println(objMap.get("integer"));
        System.out.println(objMap.get("string"));
        //Change values of underlying object
        integ=2;
        strng="Bye";
        //Check values again
        System.out.println(objMap.get("integer"));
        System.out.println(objMap.get("string"));
    }
}

And the output:

debug:
1
Hi
BUILD SUCCESSFUL (total time: 8 seconds)
Ernesto
  • 605
  • 1
  • 13
  • 30

6 Answers6

3

When you do this :

    integ=2;
    strng="Bye";

you have only changed the reference to an object not the object itself.

for Integer and String you cannot change the object as they are immutable

so if you want to change the values in your map then solutionis :

  1. remove the previous values from the map.
  2. change the values
  3. add them to your map
Community
  • 1
  • 1
nafas
  • 5,283
  • 3
  • 29
  • 57
2

You have modified the values, but haven't put them back to HashMap.

    integ=2;
    strng="Bye";
    objMap.put("integer", integ);
    objMap.put("string", strng);

I think, you are assuming that hash map will refer to the modified values. But it doesn't work that way, in this case as you are storing primitives. Your assumption will hold good if you wrap your primates inside an object.

i.e.

  public class MyClass{
     int integ;
  }
rai.skumar
  • 10,309
  • 6
  • 39
  • 55
2

You need to put the values again, so that existing values are overwritten, before you get from map again.

public static void main(String[] args) {
        //Insert objects in HashMap
        objMap.put("integer", integ);
        objMap.put("string", strng);
        //Check the values
        System.out.println(objMap.get("integer"));
        System.out.println(objMap.get("string"));
        //Change values of underlying object
        integ=2;
        strng="Bye";
        objMap.put("integer", integ);
        objMap.put("string", strng);
        //Check values again
        System.out.println(objMap.get("integer"));
        System.out.println(objMap.get("string"));
    }
Rahul Yadav
  • 1,503
  • 8
  • 11
2

I think that you need to check your Java basics, as parameters happen to be "passed by value" in Java.

This means that the objMap.put("integer", integ); will store in the map, under key "integer" the value of integ.

Changing the value of integ after this operation will have no effect on what is stored in the map, as the map contains the exact copy of the object at .put() operation time.

This approach is the opposite of the "pass by reference", where the map would contain a "pointer to" the variable integ.

devlearn
  • 1,725
  • 2
  • 17
  • 30
2

You are making a few confusions. Look at this code:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import org.junit.Before;
import org.junit.Test;

// Comment 0)
public class Test1 {
    Map<String, Object> objMap = new HashMap<>();

    private Integer integ = 1;
    private String strng = "Hi";

    // Comment 1)
    // private final Integer integ = 1;
    // private final String strng = "Hi";

    // Comment 2)
    final AtomicInteger integMutable = new AtomicInteger(1);
    final AtomicReference<String> strngMutable = new AtomicReference<>("Hi");

    @Before
    public void setup() {
        objMap.put("integer", integ);
        objMap.put("string", strng);
        objMap.put("integer2", integMutable);
        objMap.put("string2", strngMutable);
    }

    @Test
    public void test32886291() {
        // Comment 1: error raised if fields were final
        integ = 2;
        strng = "Bye";
        assertNotEquals(2, objMap.get("integer"));
        assertNotEquals("Bye", objMap.get("string"));

        integMutable.set(2);
        strngMutable.set("Bye");
        assertEquals(2, ((AtomicInteger) objMap.get("integer2")).intValue());
        assertEquals("Bye", objMap.get("string2").toString());
    }
}

Comment 0) First of all, I turned your "Test" class into a true test class using JUnit.

Comment 1) You seem confused with "field", "reference", "value" and "autoboxing" concepts. In the map, you store an object by reference (which is what you want). That's why I first replaced your int (a primitive type) with an Integer (an object).

When you do integ = 2, you are not changing the value of that object: you are re-assigning the field named "integ". Adding the "final" keyword would raise an error ("The final field Test1.integ cannot be assigned") and highlight that point. So, changing the field value (assigning to it another object) has no impact on the object stored in the map. That is confirmed by the two assertNotEquals sentences.

Comment 2) It is not possible to change the value of Integer and String which are "immutable". I replaced them with "mutable" objects respectively wrapping an int value and a String. The expected behavior is confirmed by the two assertEquals sentences.

Julien Carsique
  • 3,915
  • 3
  • 22
  • 28
1

Java uses call-by-value in this example so it stores only the actual value in the HashMap not the reference. So if you change the value you should put it again in the HashMap.

I hope it helps.

Leonid Glanz
  • 1,261
  • 2
  • 16
  • 36