Relationship Between hashCode()
and equals()
in Java
The hashCode()
and equals()
methods are closely related because they are both used to determine object equality—especially in hash-based collections like HashMap
, HashSet
, and HashTable
. To ensure proper functionality, Java enforces a contract between these methods.
🚀 The Contract Between hashCode()
and equals()
- If two objects are equal (
a.equals(b) == true
), then they must have the same hash code (a.hashCode() == b.hashCode()
).- This ensures that equal objects are stored in the same hash bucket in collections like
HashMap
.
- This ensures that equal objects are stored in the same hash bucket in collections like
- If two objects have different hash codes (
a.hashCode() != b.hashCode()
), thena.equals(b)
must returnfalse
.- This ensures that objects in different hash buckets are never equal.
- If two objects have the same hash code (
a.hashCode() == b.hashCode()
), they may or may not be equal (a.equals(b) may be true or false
).- This is because hash collisions can occur (two different objects might generate the same hash code).
🔍 Why Is This Important?
- Hash-based collections like
HashMap
andHashSet
rely on hash codes to efficiently store and retrieve objects. - When you add an object to a
HashSet
, it:- Computes the hash code using
hashCode()
. - Places the object in the corresponding hash bucket.
- If another object with the same hash code is found, it checks
equals()
to determine if they are the same object.
- Computes the hash code using
If you override equals()
but do not override hashCode()
, hash-based collections may not work correctly.
❌ What Happens If We Violate the Contract?
Case 1: Overriding equals()
Without hashCode()
If two objects are equal but have different hash codes, collections like HashSet
and HashMap
will store them in different buckets, leading to incorrect behavior.
Example (Incorrect Implementation):
class Person {
String name;
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);
}
// ❌ hashCode() is not overridden!
}
public class Main {
public static void main(String[] args) {
Set<Person> set = new HashSet<>();
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
set.add(p1);
set.add(p2);
System.out.println(set.size()); // ❌ Expected 1, but prints 2 (Incorrect)
}
}
Case 2: Overriding hashCode()
Without equals()
If two objects have the same hash code but are not considered equal, collections like HashSet
may still store duplicates.
Example (Incorrect Implementation):
class Person {
String name;
Person(String name) {
this.name = name;
}
@Override
public int hashCode() {
return name.hashCode(); // ✅ Overridden hashCode()
}
// ❌ equals() is not overridden!
}
public class Main {
public static void main(String[] args) {
Set<Person> set = new HashSet<>();
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
set.add(p1);
set.add(p2);
System.out.println(set.size()); // ❌ Expected 1, but prints 2 (Incorrect)
}
}
✅ Correctly Overriding equals()
and hashCode()
To maintain the contract between equals()
and hashCode()
, always override both methods.
Correct Implementation
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);
}
}
public class Main {
public static void main(String[] args) {
Set<Person> set = new HashSet<>();
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
set.add(p1);
set.add(p2);
System.out.println(set.size()); // ✅ Correct: Prints 1
}
}
📌 Summary
Rule | Explanation |
---|---|
1. If a.equals(b) == true , then a.hashCode() == b.hashCode() . | Ensures that equal objects go into the same hash bucket. |
2. If a.hashCode() != b.hashCode() , then a.equals(b) must be false . | Ensures different objects don’t collide. |
3. If a.hashCode() == b.hashCode() , a.equals(b) may be true or false . | Hash collisions are possible. |
✅ Always override hashCode()
when overriding equals()
!
✅ Use Objects.hash()
for easy and safe hash code generation.
✅ Follow the contract to ensure correctness in hash-based collections.
By following these rules, your objects will behave correctly in HashSet
, HashMap
, and other hash-based structures! 🚀