-9

I am quite confused about everything being a reference in most cases but sometimes not, and containers. Consider this piece of code:

HashMap<Integer,String> x_map = new HashMap<>();
x_map.put(42,"foo");
String g = x_map.get(42);
g = "bar";
System.out.println(g.equalsIgnoreCase(x_map.get(42)));

Why does this print false ?

I found the correct way to do it: How to update a value, given a key in a java hashmap?, but I am totaly lost why the above does not work as expected. Also when the objects in the map are rather large then I would like to be able to modify only a single member of one of the values in the map and currently I dont know how to do that without creating a new instance and put that into the map.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Because you don't overwrite the value in the map. The ``get`` gives you a reference to the value, then you simply reassign that reference to some other value. If you want to put a new value into the map, use ``x_map.put(42, "newValue");``. – f1sh May 29 '18 at 14:38
  • 2
    Variables are assigned by value in Java. `g = x_map.get(42)` just assigns the _value_ from the map into the variable `g`. If you reassign `g`, then you're repointing `g` to a different value. – khelwood May 29 '18 at 14:38
  • @f1sh how can i overwrite the value in the map? – 463035818_is_not_an_ai May 29 '18 at 14:39
  • You `put` something different for the same value. I.e. `x_map.put(42, "bar");`. – BeUndead May 29 '18 at 14:39
  • @user2478398 what if I dont want to put something different, but I want to modify the value that is alread in the map – 463035818_is_not_an_ai May 29 '18 at 14:40
  • @user463035818 did you try the piece of code I provided? Did you take a look at what ``put`` does? – f1sh May 29 '18 at 14:41
  • @khelwood now that makes some sense – 463035818_is_not_an_ai May 29 '18 at 14:42
  • @f1sh i tried that before, but I dont want to put a new string, i want to modify the string that is already in the map. I already got to know that this wont work with `=`. Will try to get a better example... – 463035818_is_not_an_ai May 29 '18 at 14:43
  • 2
    @user463035818 `String` objects are immutable in Java. If you want to have a mutable String, you have to write your own class. – Gyro Gearless May 29 '18 at 14:43
  • @user463035818 you cannot modify Strings in java. And what happened when you overwrite the value? – f1sh May 29 '18 at 14:44
  • Naming conventions suggest to not use underscore for variable names (except for constants (`static final`)). Instead use **camelCase**. So maybe `xMap`. Also note that you should avoid short variable names like `g`. They are not helpful for a reader to understand the code. Instead use a name that reflects its meaning/usage. Only exception are commonly used index variables like `i`, `j` or `k` in loops or size variables like `n` or `m`. – Zabuzard May 29 '18 at 14:52
  • I don't get all the down-votes on that question though. The question is well asked, provides a [mcve] and is only about understanding why this happens. OP even provided a thread showing how it should be done, indicating that he researched. I see two reasons: It's a duplicate, but then it's strange that there are no close votes. It's a *newbish* question, but that should be perfectly fine as long as the question is well asked and within [ask]. – Zabuzard May 29 '18 at 15:09

3 Answers3

3

Pass-by-value

Java is pass-by-value (see Is Java “pass-by-reference” or “pass-by-value”?).

Which means that when you do

Person first = new Person("John");
Person second = first;

you have two different variables, both pointing to the instance new Person("John") in memory. But again, both variables are different:

first  ---|
          |---> new Person("John")
second ---|

If you manipulate the object itself the change is reflected to both variables:

second.setName("Jane");
System.out.println(first.getName()); // Jane

The diagram is now:

first  ---|
          |---> new Person("John").setName("Jane")
second ---|

But if you change where a variable points to, it obviously does not affect the other variable since you didn't touch the object they point to:

second = new Person("Jane");
System.out.println(first.getName()); // John

After that statement you have two variables pointing to different objects:

first  ---> new Person("John")
second ---> new Person("Jane")

Explanation

Let's transfer that knowledge to your code. You wrote:

String g = x_map.get(42);
g = "bar";

and are asking why g = "bar" did not affect what the map stores.

As said, you only change where the variable g is pointing to. You don't manipulate the object inside the map. The diagram is first:

     |---> x_map.get(42)
g ---|
           "bar"

and then

            x_map.get(42)
g ---|
     |---> "bar"

Solution

If you want to change the object, you would need to manipulate it directly instead of only changing the variable reference. Like first.setName("Jane"). However, in Java Strings are immutable. Meaning that there is no way of manipulating a String. Methods like String#replace don't manipulate the original string, they always create a new String object and leave the old one unchanged.

So in order to change what the map stores for they key 42 you just use the Map#put method:

x_map.put(42, "bar");

This will change what x_map stores for the key 42 to "bar".

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • I was actually after modifying objects stored in a map in general, Strings being kinda special was a very unlucky coincidende. So i guess if I have a `HashMap map;` then `SomeClass g = map.get(42); g.setSomeProperty("asdf");` will just work as expected. – 463035818_is_not_an_ai May 29 '18 at 14:52
  • @user463035818 Yes, that's correct. Because `setSomeProperty` modifies the object directly. Instead of just changing where `g` points to. – Zabuzard May 29 '18 at 14:54
  • thanks for the explanation. I have to admit that I am a bit surprised about the way my question was received. I always thought the C++ corner is difficult for newbies, but here I got lots of downvotes without having a clue what is wrong with the question (other than being a lot newbie-like, is this a reason to downvote?). Nevermind, thanks again for the detailed explanation – 463035818_is_not_an_ai May 29 '18 at 15:01
  • @user463035818 Well. The down-votes probably come from you not researching enough. Since the question is answered by the [this](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) SO thread. So technically it's a duplicate. But if you ask me you couldn't really find that thread without knowing the correct terms and also the reason for your observation. Thus, and because of the detailed explanation with a [mcve], you have my up-vote. – Zabuzard May 29 '18 at 15:04
0

The reason is given in a comment by @khelwood:

Variables are assigned by value in Java. g = x_map.get(42) just assigns the value from the map into the variable g. If you reassign g, then you're repointing g to a different value.

If instead of String I put something that actually is modifiable in the map then it works just expected:

  public static class Test{
      public int x = 5;
  }

and then...

HashMap<Integer,Test> x_map = new HashMap<>();
x_map.put(42,new Test());
Test g = x_map.get(42);
g.x = 12;
System.out.println((g.x == x_map.get(42).x) + "  " + g.x + " " + x_map.get(42).x);

prints true 12 12.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

Because you didn't update the value of the 42 key in the x_map. for that you should do this

X_map.put(42, g)

Mou
  • 41
  • 1
  • 7