Reputation: 51059
Earlier I have coded HashMap to store some objects, which was expecting to use identity while storing them. I.e. objects were treated "same" if Object.equals()
was saying this.
Later I coded hashCode()
and equals()
methods for classes of these objects with content evaluating paradigm. Immediately my previous HashMap
stopped to work, because objects were mutating and becoming unequal.
How to plug some simple workaround, to make earlier code to work? May be there is a way to force HashMap
to use identity despite the fact there are equals()
and hashCode()
methods defined?
Upvotes: 1
Views: 859
Reputation: 61158
Simple answer:
Use an IdentityHashmap
.
Long answer:
It is extremely bad practice to have equals
and hashCode
on mutable properties. It in fact makes sense that the Map
stopped working if you think of this logically.
Imagine I have ColourWrapper
class:
class ColourWrapper {
private Color color;
//getter/setter omitted
@Override
public int hashCode() {
int hash = 3;
hash = 83 * hash + Objects.hashCode(this.color);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ColourWrapper other = (ColourWrapper) obj;
if (!Objects.equals(this.color, other.color)) {
return false;
}
return true;
}
}
Now I put a ColourWrapper wrapper
wrapping Color.RED
into my Map
. I later change the colour of this wrapper to Color.GREEN
. Now I want to get the value mapped to wrapper
, what would I do?
In fact I cannot. The Map
has already allocated the wrapper
to a bucket that corresponds to its hashcode (-65287
), now I mutate the wrapped Color
to green and the hash code changes.
The Map
certainly isn't told about this, so when the hash code changes its bucket does not. It is now "lost".
If you plan to use a class
as a key in a Map
then it should be immutable. In order to change a mapping:
Upvotes: 5