How do you override equals and hashCode correctly in Java, step by step?
The recipe is short and worth being able to recite without hesitating. In equals: check reference equality first, check the type second, then compare the fields that make up the identity. In hashCode: derive the value from the same fields.
Reference equality first is an optimisation and also correct — an object always equals itself. The type check is the one with a subtlety: use getClass() when the class is final, and instanceof when it is not, because a subclass that overrides equals with instanceof would break the symmetry of a getClass-based equals. Comparing the fields should use Objects.equals for reference fields, since that handles nulls on both sides.
import java.util.Objects;
public class Main {
public static void main(String[] args) {
System.out.println("same values : " + new Point(1, 2).equals(new Point(1, 2)));
System.out.println("diff values : " + new Point(1, 2).equals(new Point(1, 3)));
System.out.println("same hash : " + (new Point(1, 2).hashCode() == new Point(1, 2).hashCode()));
System.out.println("null field : " + new Point(1, 2).equals(new Point(1, 2)));
}
}
final class Point {
private final int x;
private final int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Point other = (Point) o;
return x == other.x && y == other.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}The output shows the three properties the contract requires: equal values compare equal, different values do not, and equal values produce the same hash code.
Two more things worth saying. The hash code should be stable — it must not change while the object is in a hash-based collection, because the entry is filed under the old hash and becomes unreachable. And a good hash code spreads the values out, because the map uses it to pick the bucket; returning a constant works correctly but degenerates every lookup into a linear scan.