The equals() method determines whether two objects are considered "equal". By default, it compares references (i.e., ==), but often classes (such as entities, value objects) require logical comparison based on data.
When to override:
Requirements:
Example:
public class Person { private String email; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(email, person.email); } @Override public int hashCode() { return Objects.hash(email); } }
If two objects are equal according to equals(), should their hashCode() always be the same?
Answer: Yes! This is a requirement of the Java contracts. However, the reverse is not true: two objects with the same hashCode may not be equal according to equals() — hash codes can collide for different objects.
Example of an error:
person1.equals(person2); // true person1.hashCode() != person2.hashCode(); // Error!
Story
In a corporate application, the User entity was added to a HashSet. Equals was overridden, but hashCode was not. After modifying the fields affecting equals, the HashSet "lost" this object: attempts to search using the contains method returned false, even for the same data.
Story
In an IoT project, entities were temporarily compared only by id, and then the logic was changed to use equals considering the name. The HashMap started behaving unpredictably, duplicate keys arose during updates — the equals/hashCode contract was violated due to shuffling of implementation versions.
Story
When writing an API for comparing orders, two different classes implemented their own equals, one of them called getClass(), the other used instanceof. This led to asymmetric comparison of orders and bugs when using collections and business logic.