Al comparar objetos en Java, realiza una verificación semántica , comparando el tipo y el estado de identificación de los objetos con:
- sí mismo (misma instancia)
- sí mismo (clon o copia reconstruida)
- otros objetos de diferentes tipos
- otros objetos del mismo tipo
null
Reglas:
- Simetría :
a.equals(b) == b.equals(a)
equals()
siempre cede true
o false
, pero nunca un NullpointerException
, ClassCastException
o cualquier otro arrojable
Comparación:
- Verificación de tipo : ambas instancias deben ser del mismo tipo, lo que significa que debe comparar las clases reales para determinar la igualdad. Esto a menudo no se implementa correctamente, cuando los desarrolladores lo utilizan
instanceof
para la comparación de tipos (que solo funciona mientras no haya subclases y viola la regla de simetría cuandoA extends B -> a instanceof b != b instanceof a)
.
- Comprobación semántica del estado de identificación : asegúrese de comprender en qué estado se identifican las instancias. Las personas pueden identificarse por su número de seguro social, pero no por el color de cabello (se puede teñir), el nombre (se puede cambiar) o la edad (cambia todo el tiempo). Solo con objetos de valor debe comparar el estado completo (todos los campos no transitorios); de lo contrario, verifique solo lo que identifica la instancia.
Para tu Person
clase:
public boolean equals(Object obj) {
// same instance
if (obj == this) {
return true;
}
// null
if (obj == null) {
return false;
}
// type
if (!getClass().equals(obj.getClass())) {
return false;
}
// cast and compare state
Person other = (Person) obj;
return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}
Clase de utilidad genérica reutilizable:
public final class Equals {
private Equals() {
// private constructor, no instances allowed
}
/**
* Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
*
* @param instance object instance (where the equals() is implemented)
* @param other other instance to compare to
* @param stateAccessors stateAccessors for state to compare, optional
* @param <T> instance type
* @return true when equals, false otherwise
*/
public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
if (instance == null) {
return other == null;
}
if (instance == other) {
return true;
}
if (other == null) {
return false;
}
if (!instance.getClass().equals(other.getClass())) {
return false;
}
if (stateAccessors == null) {
return true;
}
return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
}
}
Para su Person
clase, usando esta clase de utilidad:
public boolean equals(Object obj) {
return Equals.as(this, obj, t -> t.name, t -> t.age);
}