Java › Collections Framework
What is the contract between equals() and hashCode() that a custom class must satisfy to work correctly as a HashMap key or HashSet element?
IntermediateAnswer
Any two objects considered equal via equals() MUST return the identical hashCode() value (though the converse isn't required -- unequal objects may share a hash code, called a collision, which is handled but should be rare for good performance); violating this contract (overriding equals() without also overriding hashCode() consistently) causes silently broken behavior in hash-based collections, since a HashMap uses hashCode() to locate the correct bucket first, then equals() to confirm the exact match within that bucket -- if two "equal" objects hash differently, a HashMap may fail to locate an entry that logically should be found, appearing to have simply lost data.
public class Point {
private final int x, y;
// constructor omitted
@Override
public boolean equals(Object o) {
if (!(o instanceof Point p)) return false;
return x == p.x && y == p.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y); // MUST be consistent with equals()
}
}Real-world example A bug report describing a HashSet<Point> that appears to allow "duplicate" points is traced to a Point class overriding equals() (correctly comparing x/y coordinates) but forgetting to also override hashCode(), causing two logically equal Point instances to land in different buckets and never be recognized as duplicates by the HashSet.