Unravel โบ Java concepts โบ OOP and types
equals() and hashCode()
equals says when two objects count as the same; hashCode gives a number used to file objects into hash tables.
Learn these first
At a glance
A coat check.
- 1By default equals compares identity (are they the very same object?)Overriding it lets two separate objects with the same content count as equal, which is what you want for values such as a money amount or an id.
- 2The contract: if a.equals(b) is true then a.hashCode() == b.hashCode() must be trueThe reverse need not hold: different objects may share a hash.
- 3Objects.equals(a, b) and Objects.hash(f1, f2) make correct, null-safe implementations shortRecords and Lombok generate both from the fields.
- 4HashMap and HashSet use the hash to pick a bucket and then equals to find the entry inside it
- Overriding equals without hashCode is the classic bug: two equal objects land in different buckets, so set.contains(x) says no for an object that is "in" the set
- Fields used in hashCode must not change while the object is a key
- A HashMap computes hashCode, spreads the bits, and uses the result to index its bucket array
public final class Money { private final long cents; private final String currency; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Money m)) return false; return cents == m.cents && currency.equals(m.currency); } @Override public int hashCode() { return Objects.hash(cents, currency); }}- line 6 uses equals, the core of equals() and hashCode()
- line 9 uses equals, the core of equals() and hashCode()
- line 13 uses hash, the core of equals() and hashCode()
- line 14 uses hash, the core of equals() and hashCode()
Read the full explanation (about 2 min)
equals says when two objects count as the same; hashCode gives a number used to file objects into hash tables. Whenever you override one, you must override the other consistently, or sets and maps will behave wrongly.
A mental model
A coat check. The hash is the numbered hook; equals is the staff member comparing your ticket to the coat. If two equal coats get different hook numbers, you will never find yours.
How it works
By default equals compares identity (are they the very same object?). Overriding it lets two separate objects with the same content count as equal, which is what you want for values such as a money amount or an id.
The contract: if a.equals(b) is true then a.hashCode() == b.hashCode() must be true. The reverse need not hold: different objects may share a hash.
Objects.equals(a, b) and Objects.hash(f1, f2) make correct, null-safe implementations short. Records and Lombok generate both from the fields.
HashMap and HashSet use the hash to pick a bucket and then equals to find the entry inside it.
Going deeper
Overriding equals without hashCode is the classic bug: two equal objects land in different buckets, so set.contains(x) says no for an object that is "in" the set.
Fields used in hashCode must not change while the object is a key. Changing them afterwards makes the entry unreachable: it is still in the map, in the wrong bucket.
equals must be reflexive, symmetric, transitive and consistent. Mixing subclasses with extra fields breaks symmetry; prefer final classes or records for value types.
JPA entities need care: a generated id is null before saving and then changes, so basing hashCode on it moves the object between buckets.
Under the hood
A HashMap computes hashCode, spreads the bits, and uses the result to index its bucket array. A collision (same bucket) is resolved by comparing keys with equals, in a list that turns into a tree when long.
Common mistakes
- Overriding
equalsbut nothashCode. - Mutating a key after inserting it in a map.
- Comparing with
==whereequalsis meant. - Using a generated database id in
hashCodeof an entity.
How Unravel recognises it
When you paste code, Unravel looks for these signs of equals() and hashcode(). Spotting them yourself is a good habit when you read unfamiliar code:
- Types:
EqualsAndHashCode - Method calls:
Objects.hash()Objects.equals()hashCode() - Method names you declare:
equals()hashCode()
Part of a learning path
- Modeling data in modern Java ยท previous: Records ยท next: Enums
Related concepts
Builds on this
Frequently asked questions
What is equals() and hashCode()?
equals says when two objects count as the same; hashCode gives a number used to file objects into hash tables. Whenever you override one, you must override the other consistently, or sets and maps will behave wrongly.
What are the most common mistakes with equals() and hashCode()?
Overriding equals but not hashCode. Mutating a key after inserting it in a map. Comparing with == where equals is meant. Using a generated database id in hashCode of an entity.
How can I see equals() and hashCode() in real code?
Paste your own Java into Unravel and it will point out where equals() and hashcode() appears, explain how it works at the detail level you choose, and draw the flow of the code around it.