Skip to main content

Command Palette

Search for a command to run...

Overriding equals() and hashcode()

Updated
•4 min read•View as Markdown
Overriding equals() and hashcode()

0. Introduction

When discussing HashMap in Java interviews, a very common follow-up question appears after explaining hash collisions:

"Why do we need to override both equals() and hashCode()?"

However, an important point is that the rule about overriding both methods is not specific to HashMap. It is a general contract defined by Java for all classes.

Whenever objects are compared for logical equality, the relationship between equals() and hashCode() must remain consistent.

In practice, this rule becomes especially visible when working with hash-based collections such as:

  • HashMap

  • HashSet

  • Hashtable

These data structures rely on both methods to function correctly.

In this article, we use HashMap as a concrete example to illustrate why the contract between equals() and hashCode() matters and how it affects real behavior in collections.

We will cover:

  • The role of hashCode()

  • The role of equals()

  • How HashMap uses both during lookup

  • Why both methods must be overridden together


1. Role of hashCode()

The hashCode() method determines which bucket an object belongs to inside a HashMap.

When inserting a key-value pair:

map.put(key, value);

The following steps occur.

2.1. Compute the hash

Java first calls:

key.hashCode()

This produces an integer representing the object's hash value.

2.2. Determine the bucket index

The hash value is used to determine the index in the internal array.

index = (n - 1) & hash

This calculation decides which bucket the entry should be stored in.

Therefore, hashCode() is responsible for bucket selection.


2. Role of equals()

hashCode() determines which bucket a key belongs to, while equals() determines whether two keys are logically equal inside that bucket.

This becomes important when multiple keys map to the same bucket.

3.1. Collision scenario

Example:

key1.hashCode() -> bucket 3
key2.hashCode() -> bucket 3

Both keys are stored in the same bucket.

Inside that bucket, HashMap must determine which entry matches the requested key.

3.2. Key comparison

During lookup:

map.get(key)

HashMap:

  1. Computes the hash

  2. Finds the correct bucket

  3. Traverses nodes in that bucket

  4. Uses equals() to compare keys

Example bucket:

(keyA, valueA) -> (keyB, valueB) -> (keyC, valueC)

equals() determines which key matches.

Therefore, equals() is responsible for key comparison inside a bucket.


3. Why Both Must Be Overridden

Java defines a contract between equals() and hashCode().

4.1. The Contract

If two objects are considered equal:

a.equals(b) == true

Then they must return the same hash code.

a.hashCode() == b.hashCode()

If this rule is violated, HashMap may place the objects in different buckets.


4.2. Example Problem

Consider the following class:

class Person {
    String name;

    public boolean equals(Object o) {
        Person p = (Person) o;
        return this.name.equals(p.name);
    }
}

Here equals() is overridden but hashCode() is not.

Result:

Two logically equal objects may produce different hash codes.

p1.equals(p2) -> true
p1.hashCode() -> 100
p2.hashCode() -> 245

This causes them to be stored in different buckets.

When searching:

map.get(p2)

HashMap looks in the bucket determined by p2.hashCode() and fails to find the entry inserted with p1.


4. Correct Implementation

To follow the contract, both methods should be implemented together.

class Person {
    String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person p = (Person) o;
        return name.equals(p.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }
}

Now two objects with the same name will:

  • Produce the same hash code

  • Be placed in the same bucket

  • Be correctly compared using equals()


✨ Conclusion

hashCode() determines which bucket a key belongs to, while equals() determines whether two keys are logically equal. HashMap relies on both methods during insertion and lookup. Because of this relationship, overriding equals() without also overriding hashCode() can lead to incorrect behavior where keys cannot be found even though they exist in the map.