ProgrammingJava Developer

Explain the features of the equals() method in Java: when and why to override it, how to implement it correctly, and what problems may arise from its improper use.

Pass interviews with Hintsage AI assistant

Answer

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:

  • If logical identity of objects is important for your class (e.g., two users with the same email are "the same user")
  • If the object will be stored in collections (e.g., HashSet), which use equals (and hashCode)

Requirements:

  • Equals must be reflexive, symmetric, transitive, consistent, and for any non-null x, x.equals(null) must return false
  • When overriding equals, you MUST also override hashCode!

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); } }

Trick question

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!

Examples of real errors due to ignorance of the topic's subtleties


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.