The methods equals() and hashCode() play a critical role in how HashMap works under the hood.
Let’s break it down with a clear and intuitive explanation. 🧠
🔧 How HashMap stores and finds keys:
When you do:
map.put(key, value);
Step 1: Use hashCode() to find the bucket index
int hash = key.hashCode();
int index = hash % table.length;
➡️ This determines which bucket (array slot) the entry goes into.
Step 2: Use equals() to find the exact key within that bucket
Buckets can have collisions (multiple keys in one bucket). So inside the bucket, HashMap loops through entries like:
if (existingKey.equals(newKey)) {
// key already exists → overwrite value
}
🎯 So, what’s the role of each?
| Method | Role in HashMap |
|---|---|
hashCode() | Locates the bucket in the internal array |
equals() | Locates the exact key within the bucket |
⚠️ Why both are needed?
If you only override hashCode() but not equals(), HashMap might:
- Find the right bucket, but
- Fail to recognize an existing key,
- Add duplicates or miss lookups.
If you only override equals() but not hashCode(), keys that should be equal may:
- End up in different buckets,
- Become unreachable (i.e. lost).
🧪 Example (bad key class):
class BadKey {
int id;
public boolean equals(Object o) {
return o instanceof BadKey && this.id == ((BadKey)o).id;
}
// ❌ No hashCode()
}
Map<BadKey, String> map = new HashMap<>();
map.put(new BadKey(1), "value");
map.get(new BadKey(1)); // returns null ❌
✅ Example (correct key class):
class GoodKey {
int id;
public boolean equals(Object o) {
return o instanceof GoodKey && this.id == ((GoodKey)o).id;
}
public int hashCode() {
return Objects.hash(id);
}
}
Now, everything works:
map.put(new GoodKey(1), "value");
map.get(new GoodKey(1)); // returns "value" ✅
TL;DR
hashCode()→ finds the bucketequals()→ finds the right key in the bucket- Both are essential for correct behavior of
HashMap