What Happens If You Override equals()
Without Overriding hashCode()
?
If you override equals()
but do not override hashCode()
, you violate the contract between equals()
and hashCode()
. This can lead to unexpected behavior in hash-based collections like HashSet
, HashMap
, and HashTable
.
🚀 Why Is This a Problem?
The Java contract between equals()
and hashCode()
states:
- If two objects are equal (
a.equals(b) == true
), thena.hashCode() == b.hashCode()
must also be true. - If two objects have different hash codes (
a.hashCode() != b.hashCode()
), thena.equals(b)
must returnfalse
. - If two objects have the same hash code (
a.hashCode() == b.hashCode()
), they may or may not be equal (a.equals(b)
may betrue
orfalse
).- (This is because hash collisions can occur.)
🔴 Problems That Arise
1. Hash-Based Collections Will Misbehave
Hash-based collections (HashMap
, HashSet
, HashTable
) use hashCode()
for bucketing and equals()
for checking equality. If hashCode()
is not overridden, objects that are considered equal may end up in different hash buckets, causing duplicate entries or lookup failures.
Example: HashSet
Stores Duplicates Unexpectedly
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
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 Objects.equals(name, person.name);
}
// ❌ No hashCode() override!
}
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
}
}
What Went Wrong?
p1.equals(p2)
returnstrue
, meaning they should be considered the same object.- But since
hashCode()
is not overridden,p1
andp2
get different hash codes (fromObject.hashCode()
). - As a result, they are stored in different hash buckets, causing duplicates.
2. HashMap
and HashTable
Key Lookups Will Fail
If you use an object as a key in a HashMap
and override equals()
but not hashCode()
, key lookups may fail.
Example: HashMap
Key Lookup Fails
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
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 Objects.equals(name, person.name);
}
// ❌ No hashCode() override!
}
public class Main {
public static void main(String[] args) {
Map<Person, String> map = new HashMap<>();
Person p1 = new Person("Alice");
map.put(p1, "Developer");
Person p2 = new Person("Alice"); // Different object but equal by equals()
System.out.println(map.get(p2)); // ❌ Expected: "Developer", but prints: null
}
}
What Went Wrong?
p1.equals(p2)
istrue
, meaning they should be the same key.- But
p1.hashCode()
andp2.hashCode()
are different (becausehashCode()
is not overridden). HashMap
looks forp2
in a different hash bucket, so it does not find the value.
3. Performance Issues in Large Collections
- If
hashCode()
is not overridden, all objects may end up in different hash buckets, causing poor performance. - Instead of O(1) lookup time, operations may degrade to O(n) time complexity due to linear search within buckets.
✅ Correct Implementation: Override equals()
and hashCode()
To fix these issues, always override hashCode()
whenever you override equals()
.
Fixed Version
import java.util.Objects;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
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 Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name); // ✅ Includes name in hashCode
}
}
public class Main {
public static void main(String[] args) {
// HashSet test
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()); // ✅ Correct: Prints 1
// HashMap test
Map<Person, String> map = new HashMap<>();
map.put(p1, "Developer");
System.out.println(map.get(p2)); // ✅ Correct: Prints "Developer"
}
}
📌 Summary: Why You MUST Override hashCode()
With equals()
Issue | What Happens Without hashCode() ? | Why Overriding Fixes It |
---|---|---|
Duplicate Entries in HashSet | set.add(obj1) and set.add(obj2) both store objects, even if equals() says they are the same. | Objects with equal contents will have the same hash code, so duplicates are avoided. |
Failed Lookups in HashMap | map.get(new Key("Alice")) returns null , even though "Alice" is already a key. | Ensures that equal keys have the same hash code, so lookups work correctly. |
Slow Performance | Searching for an element in a hash-based collection degrades from O(1) to O(n). | Objects are placed in the correct hash bucket, making searches efficient. |
🔹 Final Best Practices
✔ Always override hashCode()
when overriding equals()
.
✔ Use Objects.hash()
for simple and safe hashCode()
implementation.
✔ Follow the contract: a.equals(b) == true
→ a.hashCode() == b.hashCode()
.
✔ Test hash-based collections (HashSet
, HashMap
) when overriding these methods.