Why must Java override hashcode when rewriting equals - an example

Keywords: Java

Entity Class

class Point {
    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)//ref Equal
        {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        Point that = (Point) obj;
        return x == that.x && y == that.y;//Contrast Value
    }
}

The above code overrides equals.

compare

@Slf4j
public class EqualsHashDemo {


    public static void compare() {
        Point a = new Point();
        a.setX(1);
        a.setY(2);

        Point b = new Point();
        b.setX(1);
        b.setY(2);

        log.info("a.equals(b) is " + a.equals(b));

    }
}

At this point the output is true

Loading objects into hashset for comparison

@Slf4j
public class EqualsHashDemo {


    public static void compare() {
        Point a = new Point();
        a.setX(1);
        a.setY(2);

        Point b = new Point();
        b.setX(1);
        b.setY(2);

        log.info("a.equals(b) is " + a.equals(b));

        HashSet<Point> points=new HashSet<>();
        points.add(a);

        log.info("points.contains(b) is " + points.contains(b)); 

    }
}

output

 a.equals(b) is true
 points.contains(b) is false

This is because hashcode has not been overridden.No override, the default is hashcode of the parent class, each object is different (hashset implementation is temporarily left out)

Override hashcode

class Point {
    private int x;
    private int y;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)//ref Equal
        {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        Point that = (Point) obj;
        return x == that.x && y == that.y;//Contrast Value
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

Run again

 a.equals(b) is true
 points.contains(b) is true

The following code can also output a normal value of 0000 after overriding hashcode

  HashMap<Point, String> map = new HashMap<>();
        map.put(a, "00000");
        log.info(map.get(b));

If not, null will be output

Posted by anatak on Thu, 16 Apr 2020 09:19:04 -0700