Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to implement equals and hashCode

Short answer

If two objects are equal by equals(), they must have the same hashCode(). That is why these methods are always overridden together:

class Point {
    final int x;
    final int y;
 
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
 
    @Override
    public boolean equals(Object o) {
        return o instanceof Point other && x == other.x && y == other.y;
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}
 
void main() {
    IO.println(new Point(1, 2).equals(new Point(1, 2)));
    IO.println(new HashSet<>(List.of(new Point(1, 2))).contains(new Point(1, 2)));
}

Output:

true
true

Simpler — a record

A record generates both methods from all its fields:

record Point(int x, int y) {}
 
void main() {
    IO.println(new Point(1, 2).equals(new Point(1, 2)));
    IO.println(new Point(1, 2).hashCode() == new Point(1, 2).hashCode());
}

Output:

true
true

Comparing by some fields

Sometimes only an identifier defines equality. Use the same fields in both methods:

class User {
    final long id;
    String name;
 
    User(long id, String name) {
        this.id = id;
        this.name = name;
    }
 
    @Override
    public boolean equals(Object o) {
        return o instanceof User other && id == other.id;
    }
 
    @Override
    public int hashCode() {
        return Long.hashCode(id);
    }
}
 
void main() {
    IO.println(new User(7, "Anna").equals(new User(7, "Anna Smith")));
}

Output:

true

Strings and null

For object fields that may be null, use Objects.equals():

class Contact {
    final String email;
 
    Contact(String email) {
        this.email = email;
    }
 
    @Override
    public boolean equals(Object o) {
        return o instanceof Contact other && Objects.equals(email, other.email);
    }
 
    @Override
    public int hashCode() {
        return Objects.hashCode(email);
    }
}
 
void main() {
    IO.println(new Contact(null).equals(new Contact(null)));
}

Output:

true

Common mistake

Overriding only equals(). The objects are equal, but a HashSet cannot find them, because it looks them up by different hash codes:

class Point {
    final int x;
 
    Point(int x) {
        this.x = x;
    }
 
    @Override
    public boolean equals(Object o) {
        return o instanceof Point other && x == other.x;
    }
}
 
void main() {
    var set = new HashSet<Point>();
    set.add(new Point(1));
 
    IO.println(new Point(1).equals(new Point(1)));
    IO.println(set.contains(new Point(1)));
}

Output:

true
false

Functions used in this recipe

  • Object.equals() — Compares objects by meaning. By default it works like ==, so classes override it.
  • Object.hashCode() — Returns the object's hash code — a number HashMap and HashSet use to find it quickly.
  • Objects.hash() — Computes a hash code from several values — for implementing hashCode().
  • Objects.equals() — Compares two objects with equals(), safely for null.

Thanks for reading!

Donate to the site — we work hard for you.