Short answer
Equal objects must have equal hash codes (the reverse need not hold), and both must be consistent over the object's lifetime.
Explanation
If you override equals() but not hashCode(), two 'equal' objects can land in different buckets, so a HashMap lookup or HashSet contains() fails to find an entry that's logically present. The other classic bug is using a mutable field in equals/hashCode and then mutating a key already in a map — the entry becomes unreachable because it's hashed under its old code.
Common mistakes
- Overriding equals without hashCode.
- Using mutable fields in hashCode for keys that change.