Learn what happens if you override hashCode() but not equals() in Java. Understand how this impacts HashMap, HashSet, and your object comparisons with simple examples.
Introduction
Imagine you’ve created a group of friends in your Java program — say, a HashSet of Person objects. You add two people who look identical (same name, age, etc.), but Java still thinks they’re different!
Confused? Many Java developers — even experienced ones — get puzzled by this. The reason lies in how equals() and hashCode() work together behind the scenes.
These two methods are like best friends — they must agree with each other. If you override one without the other, it can cause strange, hard-to-debug behavior, especially when using collections like HashMap, HashSet, or Hashtable.
In this post, we’ll explore what happens if you override hashCode() but not equals(), using simple analogies, examples, and best practices to help you write reliable, predictable Java code.
Core Concepts: Understanding equals() and hashCode()
Every Java object inherits two crucial methods from the Object class:
🟢 equals(Object obj)
Determines if two objects are meaningfully equal — for example, two Person objects having the same name and age.
By default, equals() in Object checks reference equality, meaning two objects are equal only if they are the exact same instance in memory.
You usually override equals() to define logical equality, e.g., comparing object contents instead of memory addresses.
🟣 hashCode()
Generates an integer hash value used to store and locate objects efficiently in hash-based collections such as:
HashMapHashSetLinkedHashMap
Objects that are equal according to equals() must return the same hash code. This is the famous equals()–hashCode() contract in Java.
⚠️ The Contract Between equals() and hashCode()
Here’s the rule, straight from the Java specification:
If two objects are equal according to
equals(), they must have the samehashCode().
However, the reverse is not required — two objects can have the same hash code but not be equal.
This ensures that collections like HashSet and HashMap can find and manage objects efficiently.
🚨 What Happens If You Override Only hashCode()?
If you override hashCode() but leave equals() untouched:
- Two objects with the same data may produce the same hash code.
- But since
equals()still checks for reference equality, Java considers them unequal. - As a result, collections like
HashSetwill store duplicates because they think they’re different objects!
This breaks the intended logic of “equal objects should not repeat.”
Let’s see this in action.
Code Examples
Example 1: Overriding hashCode() But Not equals()
// Java 21 Example
import java.util.HashSet;
class Person {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
// ❌ Only hashCode is overridden
@Override
public int hashCode() {
return name.hashCode() + age;
}
}
public class HashCodeOnlyExample {
public static void main(String[] args) {
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
System.out.println("p1.hashCode(): " + p1.hashCode());
System.out.println("p2.hashCode(): " + p2.hashCode());
System.out.println("Are p1 and p2 equal? " + p1.equals(p2));
HashSet<Person> people = new HashSet<>();
people.add(p1);
people.add(p2);
System.out.println("HashSet size: " + people.size());
}
}
đź§ Output Explanation:
p1.hashCode(): 63459
p2.hashCode(): 63459
Are p1 and p2 equal? false
HashSet size: 2
Even though both Person objects have identical data and same hash code, equals() wasn’t overridden — so Java treats them as different.
Your HashSet ends up storing duplicates, breaking its uniqueness property.
Example 2: Overriding Both equals() and hashCode()
// Java 21 Example
import java.util.HashSet;
import java.util.Objects;
class PersonProper {
private String name;
private int age;
PersonProper(String name, int age) {
this.name = name;
this.age = age;
}
// âś… Correctly override equals()
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // same object
if (obj == null || getClass() != obj.getClass()) return false;
PersonProper other = (PersonProper) obj;
return age == other.age && Objects.equals(name, other.name);
}
// âś… Correctly override hashCode()
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class HashCodeEqualsExample {
public static void main(String[] args) {
PersonProper p1 = new PersonProper("Alice", 25);
PersonProper p2 = new PersonProper("Alice", 25);
System.out.println("Are p1 and p2 equal? " + p1.equals(p2));
HashSet<PersonProper> people = new HashSet<>();
people.add(p1);
people.add(p2);
System.out.println("HashSet size: " + people.size());
}
}
đź§ Output Explanation:
Are p1 and p2 equal? true
HashSet size: 1
Now both objects are considered equal, and the HashSet properly avoids duplication.
This is how Java’s equals()–hashCode() partnership is meant to work.
Best Practices
Always Override Both
equals()andhashCode()Together
Whenever you define one, make sure the other is implemented consistently.Use
Objects.equals()andObjects.hash()
Introduced in Java 7, these utility methods simplify your code and handlenullvalues safely.Don’t Use Mutable Fields in Hashing or Equality
Changing fields used inequals()orhashCode()after inserting an object into aHashSetorHashMapcan lead to unpredictable results.Follow IDE Suggestions
Most modern IDEs (like IntelliJ IDEA or Eclipse) can auto-generate correct implementations ofequals()andhashCode()— use them!Test Equality Logic Thoroughly
Create test cases where two objects should be equal and where they shouldn’t. Verify both hash code consistency and equality.
Conclusion
In Java programming, equals() and hashCode() are like two wheels on a bike — if one’s missing or misaligned, your program won’t go far!
If you override only hashCode() and not equals(), collections like HashMap and HashSet may behave unpredictably — treating identical objects as different ones.
To keep your data structures accurate and your code predictable, always override both together, ensuring they follow Java’s contract. It’s a small habit that prevents big debugging headaches later.
Top comments (0)