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
trueSimpler — 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
trueComparing 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:
trueStrings 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:
trueCommon 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
falseFunctions 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.