El método equals() determina si dos objetos se consideran "iguales". Por defecto, compara referencias (es decir, ==), pero a menudo las clases (por ejemplo, entidades, objetos de valor) requieren comparación lógica basada en datos.
Cuándo sobrescribir:
Requisitos:
Ejemplo:
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); } }
Si dos objetos son iguales según equals(), ¿deben tener siempre el mismo hashCode()?
Respuesta: ¡Sí! Este es un requisito de los contratos de Java. Pero lo contrario no es cierto: dos objetos con el mismo hashCode pueden no ser iguales según equals()— los códigos hash pueden coincidir para diferentes objetos (colisiones).
Ejemplo de error:
person1.equals(person2); // true person1.hashCode() != person2.hashCode(); // ¡Error!
Historia
En una aplicación corporativa, la entidad Usuario se insertó en un HashSet. Equals fue sobrescrito, hashCode no. Después de modificar los campos que afectan equals, HashSet "perdió" este objeto: una búsqueda con el método contains devolvía false, incluso para los mismos datos.
Historia
En un proyecto de IoT, las entidades temporalmente se compararon solo por id, y luego se cambió la lógica a equals considerando el nombre. HashMap empezó a comportarse de forma impredecible, al actualizar las claves aparecieron duplicados— se violó el contrato equals/hashCode debido a la mezcla de versiones de implementación.
Historia
Al desarrollar una API para comparar pedidos, dos clases diferentes implementaron su equals, una de ellas llamaba a getClass(), y la otra— instanceof. Esto llevó a una comparación no simétrica de los pedidos y errores al usar colecciones y lógica de negocio.