Fundamentals 10 min read

Understanding HashMap: Why Overriding hashCode and equals Is Crucial for Custom Key Objects

The article explains how HashMap stores data using hash functions, illustrates hash collisions and chain addressing, and demonstrates through Java code why overriding both hashCode and equals in custom key classes is essential for correct retrieval from a HashMap.

Java Captain
Java Captain
Java Captain
Understanding HashMap: Why Overriding hashCode and equals Is Crucial for Custom Key Objects

1. Understanding HashMap Efficiency Through Hash Algorithms

First, recall a data‑structure concept: in a linear list of length n (e.g., an ArrayList with 10,000 elements) searching for a specific number requires scanning from the start, averaging n/2 comparisons.

In contrast, a hash table’s average lookup is close to 1 because each element’s storage position is determined by a hash function.

Assume a simple hash function x*x%5 and a hash table of length 11. Inserting 6 yields index 1, inserting 7 yields index 4, as shown in the figure.

Thus, to find element 6 we compute its hash and directly access index 1.

However, hash collisions can occur. For example, 7 and 8 may map to the same index; Java’s HashMap resolves this with the “separate chaining” method, illustrated in the next figure.

The approach creates a linked list for all entries that share the same hash index. When inserting 8, a new node is added to the chain at index 4; when searching for 8, the chain is traversed until the matching key is found.

Although collisions cannot be eliminated entirely, a well‑designed hash function keeps the chain length reasonable. This theoretical background explains why correctly overriding hashCode is important.

2. Why You Must Override equals and hashCode

When a HashMap stores instances of a custom class as keys, failing to override equals and hashCode leads to unexpected behavior. The following example, WithoutHashCode.java , demonstrates the problem.

import java.util.HashMap;
class Key {
    private Integer id;
    public Integer getId() { return id; }
    public Key(Integer id) { this.id = id; }
    // intentionally comment out equals and hashCode
    // public boolean equals(Object o) {
    //     if (o == null || !(o instanceof Key)) { return false; }
    //     else { return this.getId().equals(((Key) o).getId()); }
    // }
    // public int hashCode() { return id.hashCode(); }
}
public class WithoutHashCode {
    public static void main(String[] args) {
        Key k1 = new Key(1);
        Key k2 = new Key(1);
        HashMap
hm = new HashMap<>();
        hm.put(k1, "Key with id is 1");
        System.out.println(hm.get(k2));
    }
}

k1 and k2 have the same id (1) but are distinct objects. The map stores k1, yet retrieving with k2 returns null because the default Object.hashCode returns the object's memory address, causing different hash values for k1 and k2.

After uncommenting the hashCode method, both keys produce the same hash (e.g., 100). However, the lookup still fails because the default Object.equals compares memory addresses, so k1 and k2 are not considered equal.

HashMap uses separate chaining to handle collisions; multiple entries can reside at the same bucket. Even with identical hash values, equals must confirm that the retrieved object matches the requested key.

Therefore, to make k2 retrieve the stored value, you must also override equals to compare the id fields, ensuring that two Key objects with the same id are considered equal.

3. Explanation of the Interview Question

Because HashMap is frequently used in projects, interviewers often ask whether candidates have overridden hashCode and equals for custom key objects and how they implemented them.

The takeaway is clear: whenever you use a custom object as a HashMap key, you must provide proper implementations of both equals and hashCode; otherwise, lookups will fail.

JavainterviewHashMapdata-structuresequalsHashCode
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.