2.8 The equals() & hashCode() Contract
← Back to Chapter 2: Java Overview & Memory Model
Overriding equals() and hashCode() correctly is one of the most critical requirements for data structures like HashMap, HashSet, and Hashtable.
1. The Mathematical Contract
Per the Java Language Specification (JLS):
- If two objects are equal via
equals(Object), they MUST have the samehashCode():a.equals(b) == true ===> a.hashCode() == b.hashCode() - If two objects have the same
hashCode(), they are NOT necessarily equal (Hash Collision):a.hashCode() == b.hashCode() ===> a.equals(b) may be true OR false - Consistency: Successive calls to
hashCode()on the same object must return identical integers, provided state used inequals()is unmodified.
2. What Breaks If You Override equals() Without hashCode()?
public class Product {
private final String sku;
public Product(String sku) { this.sku = sku; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Product p)) return false;
return Objects.equals(sku, p.sku);
}
// OMITTED hashCode()!
}
The Catastrophic Bug:
Map<Product, Integer> inventory = new HashMap<>();
inventory.put(new Product("SKU-99"), 50);
// Retrieval fails!
Integer count = inventory.get(new Product("SKU-99"));
System.out.println(count); // PRINTS null!
Why?
The new lookup key new Product("SKU-99") inherits default Object.hashCode() (derived from its memory address). It hashes to a different bucket in the HashMap, so the map never checks equals() and returns null.
3. Idiomatic Implementation with java.util.Objects
import java.util.Objects;
public class Employee {
private final long id;
private final String email;
public Employee(long id, String email) {
this.id = id;
this.email = email;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return id == employee.id && Objects.equals(email, employee.email);
}
@Override
public int hashCode() {
return Objects.hash(id, email);
}
}