It is not always necessary to override hashcode and equals. But if you think you need to override one, then you need to override both of them.
Collections such as HashMap and HashSet use the hashcode value of an object to determine how the object should be stored in the collection, and the hashcode is used again to help locate the object in the collection.
Hashing retrieval is a two-step process.
- Find the right bucket (using hashCode())
- Search the bucket for the right element (using equals() )
What happens when we override only one of them :
Override only
hashCode
Imagine you have this
MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");
If you only override
hashCode
then when you call myMap.put(first,someValue)
it takes first, calculates its hashCode
and stores it in a given bucket. Then when you call myMap.put(second,someOtherValue)
it should replace first with second as per the Map Documentation because they are equal (according to our definition).
But the problem is that equals was not redefined, so when the map hashes
second
and iterates through the bucket looking if there is an object k
such that second.equals(k)
is true it won't find any as second.equals(first)
will be false
.
Override only
equals
If only
equals
is overriden, then when you call myMap.put(first,someValue)
first will hash to some bucket and when you call myMap.put(second,someOtherValue)
it will hash to some other bucket (as they have a different hashCode
). So, although they are equal, as they don't hash to the same bucket, the map can't realize it and both of them stay in the map.Below is the sample example code :
public class MyClass { private final String importantField; private final String anotherField; public MyClass(final String equalField, final String anotherField) { this.importantField = equalField; this.anotherField = anotherField; } public String getEqualField() { return importantField; } public String getAnotherField() { return anotherField; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((importantField == null) ? 0 : importantField.hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final MyClass other = (MyClass) obj; if (importantField == null) { if (other.importantField != null) return false; } else if (!importantField.equals(other.importantField)) return false; return true; } }
No comments:
Post a Comment