The equals/hashCode Contract
intermediate14 min readLesson 64 of 180
The pairing rule that keeps HashSet and HashMap correct, and the mutable-key trap that makes contains lie.
The equals/hashCode contract
Write equals() and you must write hashCode(). The contract:
- Equal objects must have equal hash codes.
- Unequal objects may share a hash code (collision) — but shouldn't, or hash-based collections degrade toward lists.
Break the pairing and HashSet/HashMap silently misbehave. The loudest
failure is the mutable key trap: put a mutable object in a HashSet,
then mutate a field it hashes on — the object stays in its old bucket,
so contains returns false even though equals says it should be there:
Set<Point> pts = new HashSet<>(); // mutable Point
pts.add(p);
p.x = 99; // hashCode changes under the set
pts.contains(p); // false! — searches the wrong bucket
That is why hash keys should be immutable.
Rules for hand-written equals:
- parameter is
Object, then narrow withinstanceof - reflexive, symmetric, transitive, consistent, never
null == true @Overrideso a typo likeequals(Point)fails the build
hashCode should mix all fields used in equals:
Objects.hash(x, y) does it correctly and consistently.