Me encontré con un problema interesante (y muy frustrante) con el equals()
método hoy que causó el bloqueo de lo que pensé que era una clase bien probada y causó un error que me llevó mucho tiempo rastrear.
Solo para completar, no estaba usando un IDE o depurador, solo un buen editor de texto antiguo y System.out. El tiempo era muy limitado y era un proyecto escolar.
De todos modos
Que estaba desarrollando un carrito de la compra básica que podría contener un ArrayList
de Book
los objetos . Con el fin de poner en práctica los addBook()
, removeBook()
y hasBook()
métodos de la Cesta, quería comprobar si el Book
ya existía en el Cart
. Entonces me voy
public boolean equals(Book b) {
... // More code here - null checks
if (b.getID() == this.getID()) return true;
else return false;
}
Todo funciona bien en las pruebas. Creo 6 objetos y los lleno con datos. Realiza muchas operaciones de adición, eliminación, has () en Cart
y todo funciona bien. Leí que puedes tener equals(TYPE var)
oequals(Object o) { (CAST) var }
asumir que, dado que funcionaba, no importaba demasiado.
Luego me encontré con un problema: necesitaba crear un Book
objeto con solo el contenido ID
dentro de la clase Libro. No se ingresarán otros datos. Básicamente lo siguiente:
public boolean hasBook(int i) {
Book b = new Book(i);
return hasBook(b);
}
public boolean hasBook(Book b) {
// .. more code here
return this.books.contains(b);
}
De repente, el equals(Book b)
método ya no funciona. Esto tomó MUCHO tiempo para rastrear sin un buen depurador y suponiendo que la Cart
clase se probó y corrigió correctamente. Después de cambiar el equals()
método a lo siguiente:
public boolean equals(Object o) {
Book b = (Book) o;
... // The rest goes here
}
Todo comenzó a funcionar nuevamente. ¿Hay alguna razón por la cual el método decidió no tomar el parámetro Libro a pesar de que claramente era un Book
objeto? La única diferencia parecía ser que se instanciaba dentro de la misma clase y solo se llenaba con un miembro de datos. Estoy muy muy confundido Por favor, arrojar algo de luz?
fuente
Respuestas:
En Java, el
equals()
método que se heredaObject
es:En otras palabras, el parámetro debe ser de tipo
Object
. Esto se llama anulación ; su métodopublic boolean equals(Book other)
hace lo que se llama sobrecarga alequals()
método.Los
ArrayList
usos sobrescritosequals()
métodos para comparar los contenidos (por ejemplo, para sucontains()
yequals()
métodos), no sobrecargados queridos. En la mayoría de su código, llamar al que no anuló correctamenteObject
los iguales estuvo bien, pero no es compatible conArrayList
.Por lo tanto, no anular el método correctamente puede causar problemas.
Anulo es igual a lo siguiente cada vez:
El uso de la
@Override
anotación puede ayudar mucho con errores tontos.Úselo siempre que piense que está anulando el método de una superclase o interfaz. De esa manera, si lo hace de manera incorrecta, obtendrá un error de compilación.
fuente
if (!(other instanceof MyClass))return false;
devuelvefalse
siMyClass
extiende la otra clase. Pero no volveríafalse
si la otra clase se extendieraMyClass
. ¿No deberíaequal
ser menos contradictorio?Si usa eclipse solo vaya al menú superior
fuente
Ligeramente fuera de tema a su pregunta, pero probablemente vale la pena mencionar de todos modos:
Commons Lang tiene algunos métodos excelentes que puedes usar para anular equals y hashcode. Consulte EqualsBuilder.reflectionEquals (...) y HashCodeBuilder.reflectionHashCode (...) . Me ahorró mucho dolor de cabeza en el pasado, aunque, por supuesto, si solo quiere hacer "iguales" en la identificación, puede que no se ajuste a sus circunstancias.
También estoy de acuerdo en que debe usar la
@Override
anotación siempre que anule iguales (o cualquier otro método).fuente
right click -> source -> generate hashCode() and equals()
,Otra solución rápida que ahorra código repetitivo es la anotación Lombok EqualsAndHashCode . Es fácil, elegante y personalizable. Y no depende del IDE . Por ejemplo;
Vea las opciones disponibles para personalizar qué campos usar en los iguales. Lombok está disponible en maven . Simplemente agréguelo con el alcance proporcionado :
fuente
en Android Studio es alt + insert ---> equals y hashCode
Ejemplo:
fuente
Considerar:
fuente
obj
se declara como unObject
. El punto de herencia es que luego puede asignar unBook
aobj
. Después de eso, a menos que sugiera que unObject
no debería ser comparable a unaString
víaequals()
, este código debería ser perfectamente legal y de devoluciónfalse
.la
instanceOf
declaración se usa a menudo en la implementación de iguales.¡Esta es una trampa popular!
El problema es que el uso
instanceOf
viola la regla de simetría:(object1.equals(object2) == true)
si y solo si(object2.equals(object1))
si el primer igual es verdadero y object2 es una instancia de una subclase de la clase a la que pertenece obj1, ¡el segundo igual devolverá falso!
si la clase considerada a la que pertenece ob1 se declara como final, entonces este problema no puede surgir, pero en general, debe probar lo siguiente:
this.getClass() != otherObject.getClass();
si no, devuelve falso, de lo contrario, pruebe los campos para comparar la igualdad.fuente
equals()
método. Recomienda contra el usogetClass()
. La razón principal es que hacerlo rompe el Principio de sustitución de Liskov para las subclases que no afectan la igualdad.recordId es propiedad del objeto
fuente