In Java, the hashCode()
and equals()
methods play a pivotal role in how objects behave in hash-based collections like HashMap
, HashSet
, and Hashtable
. If you're a Java developer (or prepping for interviews), understanding this contract is non-negotiable.
Let’s break it all down with rules, rationale, examples, and best practices.
🧠 Why is the hashCode
and equals
Contract Important?
When objects are stored in hash-based collections:
hashCode()
decides the bucket (index).equals()
checks logical equality between objects in that bucket.
If the contract is broken, collections like HashMap
and HashSet
can behave incorrectly — e.g., duplicate entries, lookup failures, or performance issues.
🔁 equals()
Method Contract
The equals()
method defines logical equality. The Java specification defines five rules it must follow:
1. Reflexive
An object must equal itself.
java
x.equals(x) == true
2. Symmetric
If one object equals another, the reverse must also be true.
java
if (x.equals(y)) then y.equals(x)
3. Transitive
If x.equals(y)
and y.equals(z)
, then x.equals(z)
must also be true.
java
if (x.equals(y) && y.equals(z)) then x.equals(z)
4. Consistent
If no changes are made, repeated invocations of equals()
must return the same result.
java
x.equals(y) consistently returns true or false
5. Non-null
Comparing with null
should always return false.
java
x.equals(null) == false
🔢 hashCode()
Method Contract
The hashCode()
method returns an integer used to determine an object’s hash bucket in a hash-based collection.
The rules:
1. Consistent
The hash code must stay the same unless the object’s fields used in equals()
change.
java
x.hashCode() must return the same value on every call
2. Equal Objects → Equal Hash Codes
If two objects are equal via equals()
, their hash codes must be the same.
java
if (x.equals(y)) then x.hashCode() == y.hashCode()
3. Unequal Objects → Prefer Different Hash Codes
Not mandatory, but it’s good practice for performance.
java
if (x.equals(y) == false) it's better if x.hashCode() != y.hashCode()
🚨 What Happens If You Break the Contract?
- Equal objects with different hash codes will go into different buckets → lookup fails.
- Unequal objects with the same hash code will go into the same bucket → performance drops due to linear scans.
💡 Correct Implementation Example
Here’s how you can safely override equals()
and hashCode()
using Java best practices:
java
import java.util.Objects;
public class Person {
private String name;
private int age;
// Constructor, getters, setters omitted for brevity
@Override
public boolean equals(Object o) {
if (this == o) return true; // Reflexive
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age); // Uses fields from equals()
}
}
Why this works:
equals()
compares the same fields used in hashCode()
.Objects.hash()
generates a reliable hash code.- Covers all required contract rules.
🛡️ Best Practices
- Always override both
equals()
and hashCode()
together. - Use
Objects.equals()
and Objects.hash()
for simplicity and null-safety. - Keep both methods consistent: the same fields must be used in both.
🎯 Summary
MethodPurposeKey Ruleequals()
Logical equalityEqual objects must behave identicallyhashCode()
Hash bucket indexEqual objects must have equal hash codes
Violating the contract breaks the behavior of collections like HashMap
and HashSet
.
By following this contract, you ensure that your Java classes behave reliably in collections and are safe for use in enterprise-grade applications.