bluehallu
bluehallu

Reputation: 10285

Changing an object which is used as a Map key

Let V be a class with a single attribute named K and its getter and setters.

What's supposed to happen if I do:

V v = new V();
v.setK("a");
HashMap<K,V> map = new HashMap<K,V>();
map.put(v.getk(),v);
v.setK("b");

As far as I know, this should cause some kind of problem because a map key is supposed to be invariable. What would happen here?

Edit: Consider the key not to be a String but a mutable object as stated in the coment below.

Upvotes: 3

Views: 4861

Answers (5)

Vadim Ponomarev
Vadim Ponomarev

Reputation: 1346

Quote from "Map" interface JavaDoc:

Great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.

You simply shouldn't mutate keys (in the way which changes their "hashCode"/"equals"). You will definitely have very long and awful debugging if you try.

It's like you swap books in the library. Index became unreliable. You search for "Bradbury", but find "Simak".

Upvotes: 6

Marko Topolnik
Marko Topolnik

Reputation: 200168

The title of this question is misleading -- you are not changing the map key, as in mutating the object used as map key. When you say map.put(x, y), you are creating a map entry that aggregates two independent values: a key and a value. Where the key originates from is not seen by the map, it's just two objects. So, you have created a map entry ("a", v) and after that you just changed the state of v -- there is no way this could have influenced the map entry's key "a". If, on the other hand, you had an object K of your own making, like

public class K { 
  private String s;
  public K(String s) { this.s = s; }
  public void setS(String s) { this.s = s; }
  public boolean equals(Object o) { return ((K)o).s.equals(this.s); }
  public int hashCode() { return s.hashCode(); }

}

and now you do

final K k = new K("a");
map.put(k, v);
k.setS("b");
map.get(k);

then you would face the problem -- you mutated the object used as the map key.

Upvotes: 1

htulsiani
htulsiani

Reputation: 344

V v = new V();
v.setK("a");
HashMap<K,V> map = new HashMap<K,V>();
map.put(v.getk(),v);

//Nothing will change in the hashmap with this step
v.setK("b");

but the problem will be while fetching the object V from map. If you call map.get(v.getk()), you will get null because the value in the map is mapped with object "a". However, since this String "a" is inter you can always fetch this object from map by map.get("a"); or

V v = new V();
v.setK("a");
map.get(v.getK());

PS: I have not tried to run this

Upvotes: 2

Martijn Courteaux
Martijn Courteaux

Reputation: 68857

By calling v.setK(), you aren't changing the key in the HashMap. So you will simply have wrong information in your V object.

Upvotes: 1

Bohemian
Bohemian

Reputation: 425043

If you were trying to look up the map using v.getk() it wouldn't find an entry, because you've changed the value return by the getter on v.

Or in other words, the map isn't magically kept in sync with what happens to your v object - it uses (and keeps using) the value given to it in the put().

Upvotes: 2

Related Questions