Why hashCode Must Be Overridden When equals Is Overridden in Java

Entity Class Definition

Let's define a simple Rectangle class that overrides the equals method to compare objects based on their width and height values instead of reference equality.

class Rectangle {
    private int width;
    private int height;

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        Rectangle other = (Rectangle) obj;
        return width == other.width && height == other.height;
    }
}

Testing Object Equality

When we create two Rectangle objects with the same width and height values, the equals method returns true as expected.

@Slf4j
public class EqualityDemo {

    public static void testEquality() {
        Rectangle rect1 = new Rectangle();
        rect1.setWidth(10);
        rect1.setHeight(5);

        Rectangle rect2 = new Rectangle();
        rect2.setWidth(10);
        rect2.setHeight(5);

        log.info("rect1.equals(rect2) is " + rect1.equals(rect2));
    }
}

Output:

rect1.equals(rect2) is true

The Problem: Using HashSet

Now let's add these two logically equal objects to a HashSet and check if the set can find the second object.

@Slf4j
public class EqualityDemo {

    public static void testHashSet() {
        Rectangle rect1 = new Rectangle();
        rect1.setWidth(10);
        rect1.setHeight(5);

        Rectangle rect2 = new Rectangle();
        rect2.setWidth(10);
        rect2.setHeight(5);

        log.info("rect1.equals(rect2) is " + rect1.equals(rect2));

        HashSet<Rectangle> shapes = new HashSet<>();
        shapes.add(rect1);

        log.info("shapes.contains(rect2) is " + shapes.contains(rect2));
    }
}

Output:

rect1.equals(rect2) is true
shapes.contains(rect2) is false

This is unexpected! Two objects that are equal according to equals() cannot be found in a HashSet. This happens becuase hashCode() was not overridden. By default, each object receives a hash code based on its memory location, so rect1 and rect2 have different hash codes even though they are logically equal.

The Solution: Override hashCode

To fix this issue, we need to override the hashCode method to return the same value for objects with equal field values.

class Rectangle {
    private int width;
    private int height;

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        Rectangle other = (Rectangle) obj;
        return width == other.width && height == other.height;
    }

    @Override
    public int hashCode() {
        return Objects.hash(width, height);
    }
}

Verification

After overriding hashCode, both HashSet and HashMap work correct with equal objects.

HashSet<Rectangle> shapes = new HashSet<>();
shapes.add(rect1);

log.info("shapes.contains(rect2) is " + shapes.contains(rect2));

HashMap<Rectangle, String> map = new HashMap<>();
map.put(rect1, "blue");
log.info("map.get(rect2) is " + map.get(rect2));

Output:

shapes.contains(rect2) is true
map.get(rect2) is blue

Without overriding hashCode, the HashMap lookup would return null becuase the two equal objects hash to different bucket locations.

Tags: java hashCode equals HashSet hashmap

Posted on Wed, 13 May 2026 13:15:07 +0000 by nolos