Fundamentals 11 min read

Understanding the Relationship Between hashCode() and equals() in Java

This article explains how Java's hashCode() and equals() methods interact, illustrates their behavior with and without hash‑based collections through multiple code examples, and outlines the essential principles developers must follow when overriding these methods to ensure correct functionality in hash tables.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Understanding the Relationship Between hashCode() and equals() in Java

When using Java's equals() to compare two objects, the hashCode() method provides an integer hash used by hash‑based collections such as HashSet , HashMap , and Hashtable . The article examines the relationship between these two methods in two scenarios.

Scenario 1: No hash‑based collection is created

If a class is never stored in a hash‑based collection, hashCode() has no effect on equality checks; only equals() matters. The example shows two Person objects that are equal according to equals() but have different hash codes, resulting in distinct entries when added to a HashSet .

import java.util.*;
public class NormalHashCodeTest {
    public static void main(String[] args) {
        Person p1 = new Person("eee", 100);
        Person p2 = new Person("eee", 100);
        Person p3 = new Person("aaa", 200);
        System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
        System.out.printf("p1.equals(p3) : %s; p1(%d) p3(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode());
    }
    private static class Person {
        int age; String name;
        public Person(String name, int age) { this.name = name; this.age = age; }
        @Override public boolean equals(Object obj) {
            if (obj == null) return false;
            if (this == obj) return true;
            if (this.getClass() != obj.getClass()) return false;
            Person other = (Person) obj;
            return name.equals(other.name) && age == other.age;
        }
    }
}

Output shows that p1.equals(p2) is true, but their hash codes differ, so a HashSet would treat them as distinct.

Scenario 2: A hash‑based collection is created

When objects are stored in a hash‑based collection, the contract requires that equal objects must have identical hash codes. The article demonstrates this with two tests:

If two objects are equal, their hashCode() values must be the same.

Objects with identical hash codes are not necessarily equal (hash collisions).

First test (only equals() overridden) still produces duplicate entries in a HashSet because the hash codes differ.

import java.util.*;
public class ConflictHashCodeTest1 {
    public static void main(String[] args) {
        Person p1 = new Person("eee", 100);
        Person p2 = new Person("eee", 100);
        Person p3 = new Person("aaa", 200);
        HashSet set = new HashSet();
        set.add(p1); set.add(p2); set.add(p3);
        System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
        System.out.printf("set:%s\n", set);
    }
    private static class Person {
        int age; String name;
        public Person(String name, int age) { this.name = name; this.age = age; }
        @Override public boolean equals(Object obj) { /* same as above */ }
    }
}

Second test overrides both equals() and hashCode() so that equal objects share the same hash code, eliminating duplicates in the HashSet .

import java.util.*;
public class ConflictHashCodeTest2 {
    public static void main(String[] args) {
        Person p1 = new Person("eee", 100);
        Person p2 = new Person("eee", 100);
        Person p3 = new Person("aaa", 200);
        Person p4 = new Person("EEE", 100);
        HashSet set = new HashSet();
        set.add(p1); set.add(p2); set.add(p3);
        System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
        System.out.printf("p1.equals(p4) : %s; p1(%d) p4(%d)\n", p1.equals(p4), p1.hashCode(), p4.hashCode());
        System.out.printf("set:%s\n", set);
    }
    private static class Person {
        int age; String name;
        public Person(String name, int age) { this.name = name; this.age = age; }
        @Override public int hashCode() {
            int nameHash = name.toUpperCase().hashCode();
            return nameHash ^ age;
        }
        @Override public boolean equals(Object obj) { /* same as above */ }
    }
}

Output confirms that p1 and p2 are considered equal (same hash code and equals() true), while p1 and p4 have identical hash codes but are not equal because the names differ in case.

Principles

1. The hash code of an unchanged object must remain constant across invocations.

2. Equal hash codes do not guarantee object equality; both hashCode() and equals() are needed to uniquely identify objects.

3. Whenever equals() is overridden, hashCode() must also be overridden, using the same fields that determine equality.

Failing to keep these contracts can cause incorrect behavior in hash‑based collections such as HashMap and HashSet .

JavaprogrammingInterviewHashMapHashSetequalsHashCodeobject
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.