The hashCode/equals contract
Hash-based collections (HashSet, HashMap) find an entry's bucket using hashCode(), then confirm the
match using equals(). If you override equals() without also overriding hashCode(), two "equal" objects
can land in different buckets — so a HashSet will silently contains() == false for an object it should
logically consider a duplicate. The class below deliberately overrides only equals() to show the break.
import java.util.*;
class Bad {
int v;
Bad(int v) { this.v = v; }
@Override public boolean equals(Object o) { return o instanceof Bad b && b.v == v; }
// no hashCode() override -> falls back to identity hash, contract broken
}
Set<Bad> set = new HashSet<>();
Bad b1 = new Bad(5);
set.add(b1);
System.out.println("contains(new Bad(5)) [equal by value]: " + set.contains(new Bad(5)));
System.out.println("contains(b1) [same reference]: " + set.contains(b1));