Dims
Dims

Reputation: 51059

How to force HashMap to use identity (hash code)? or suggest workaround

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

Answers (1)

Boris the Spider
Boris the Spider

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:

  1. Remove the previous mapping
  2. Create a new key
  3. Put the new mapping into the map

Upvotes: 5

Related Questions