Short answer
The contract requires that equal objects have equal hash codes; if you override equals to compare by fields but leave the identity hashCode, two logically equal objects land in different buckets and the map fails to find what you inserted.
Explanation
Conversely overriding only hashCode without equals means lookups fall back to identity equality and still miss. The production symptom is a put followed by a get returning null, or duplicate entries in a HashSet, which is why you always override both together, typically via Objects.hash and Objects.equals.
Common mistakes
- Overriding equals without hashCode.
- Writing hashCode from fields that equals ignores.