🚀 Rules for Overriding hashCode()
in Java
When overriding hashCode()
, follow these rules to ensure correctness, efficiency, and compliance with Java collections like HashMap
, HashSet
, and HashTable
.
1️⃣ Follow the equals()
–hashCode()
Contract
The most important rule:
If two objects are equal (
a.equals(b) == true
), thena.hashCode() == b.hashCode()
must also betrue
.However, if two objects are not equal, their hash codes may or may not be different.
Why is this important?
Hash-based collections (HashMap
, HashSet
) use hashCode()
to group objects into buckets before checking equals()
. If this contract is violated, data retrieval may fail.
❌ Bad Example: Violating the Contract
class Person {
private String name;
public Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
// ❌ Violates the contract (Different hashCodes for equal objects)
@Override
public int hashCode() {
return (int) (Math.random() * 1000); // Bad! Produces random values
}
}
📌 Problem: Equal Person
objects (equals()
returns true
) may get different hash codes, breaking HashSet
and HashMap
functionality.
✅ Fixed Version
@Override
public int hashCode() {
return Objects.hash(name); // Ensures same hash for equal objects
}
2️⃣ Use the Same Fields in hashCode()
as in equals()
When overriding hashCode()
, include only the fields used in equals()
. This ensures consistent hashing.
✅ Correct Example
import java.util.Objects;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age); // ✅ Uses same fields as equals()
}
}
📌 Why is this correct?
equals()
comparesname
andage
, sohashCode()
must use the same fields.- Ensures equal objects have the same hash code.
3️⃣ Ensure Consistency: hashCode()
Must Always Return the Same Value for the Same Object
If an object does not change,
hashCode()
must return the same value every time it is called.
❌ Bad Example
@Override
public int hashCode() {
return (int) (System.nanoTime() % 1000); // ❌ Changes on every call!
}
📌 Problem: hashCode()
changes constantly, breaking HashSet
and HashMap
operations.
✅ Fixed Version
@Override
public int hashCode() {
return Objects.hash(name, age);
}
4️⃣ Avoid Using Mutable Fields in hashCode()
If a field used in
hashCode()
changes after an object is inserted into aHashMap
, it may be lost!
❌ Bad Example: Using a Mutable Field in hashCode()
class Person {
private String name;
private int age;
private double salary; // ❌ Mutable field
@Override
public int hashCode() {
return Objects.hash(name, age, salary); // ❌ Salary can change!
}
}
📌 Problem:
- If
salary
changes after adding the object to aHashMap
,hashCode()
will change. - The object may not be found when trying to retrieve it.
✅ Fixed Version
@Override
public int hashCode() {
return Objects.hash(name, age); // ✅ Excludes mutable field
}
📌 Solution: Only use immutable fields in hashCode()
.
5️⃣ Use Objects.hash()
or a Prime Number Formula
✅ Preferred: Objects.hash()
(Simple & Safe)
@Override
public int hashCode() {
return Objects.hash(name, age, email);
}
📌 Why?
- Handles
null
values safely. - Generates consistent hash codes.
✅ Alternative: Prime Number Multiplication
@Override
public int hashCode() {
int result = 17; // Start with a prime number
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
return result;
}
📌 Why 31
?
31
is a prime number, reducing hash collisions.
6️⃣ When Overriding hashCode()
, Always Override equals()
Overriding one without the other can break
HashMap
andHashSet
behavior.
❌ Bad Example: Overriding hashCode()
Without equals()
@Override
public int hashCode() {
return Objects.hash(name);
}
📌 Problem:
- If
equals()
is not overridden, objects will be compared using==
instead of their content.
✅ Fixed Version: Override Both
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
📌 Ensures equals()
and hashCode()
are consistent for collections like HashMap
.
📌 Summary: Rules for Overriding hashCode()
Rule | Why It Matters |
---|---|
1. If equals() returns true , hashCode() must return the same value. | Ensures objects in HashSet and HashMap work correctly. |
2. Use the same fields in hashCode() as in equals() . | Guarantees consistency. |
3. Ensure hashCode() always returns the same value for the same object. | Prevents unexpected behavior in collections. |
4. Avoid using mutable fields in hashCode() . | Ensures objects can be found after being inserted into a HashMap . |
5. Use Objects.hash() or prime numbers for hashing. | Creates a strong, consistent hash function. |
6. Always override equals() when overriding hashCode() . | Ensures logical equality and proper collection behavior. |
✅ Final Best Practices
✔ Always override hashCode()
when overriding equals()
.
✔ Use Objects.hash()
for simplicity and correctness.
✔ Only use immutable fields in hashCode()
.
✔ Test with HashMap
and HashSet
to verify correctness.
By following these rules, your Java objects will work correctly, efficiently, and predictably in hash-based collections! 🚀