Pregunta

Me encontré con un problema interesante (y muy frustrante) con el método equals () hoy que causó el bloqueo de lo que creía que era una clase bien probada y causó un error que me llevó muy mucho tiempo para 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 -

Estaba desarrollando un carrito de compras básico que podía contener una ArrayList de Book objetos . Para implementar los métodos addBook () , removeBook () y hasBook () del Carrito, quería comprobar si el < code> Libro ya existía en el Carrito . 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. Realice muchas operaciones de agregar, eliminar, tiene () en el Carrito y todo funciona bien. Leí que puedes tener igual a (TYPE var) o igual a (Object o) {(CAST) var} pero asumí que ya que estaba funcionando, no importaba demasiado.

Luego me encontré con un problema: necesitaba crear un objeto Book con solo el ID dentro de la clase Book. 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 método igual (Libro b) ya no funciona. Esto tomó MUCHO tiempo para rastrear sin un buen depurador y suponiendo que la clase Cart se probó y corrigió correctamente. Después de cambiar el método equals () 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 objeto Libro ? 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?

¿Fue útil?

Solución

En Java, el método equals () que se hereda de Object es:

public boolean equals(Object other);

En otras palabras, el parámetro debe ser de tipo Object .

La ArrayList utiliza el método de igualdad correcto, en el que siempre llamaba al que no anulaba correctamente la igualdad de Object .

No anular el método correctamente puede causar problemas.

Anulo es igual a lo siguiente cada vez:

@Override
public boolean equals(Object other){
    if (other == null) return false;
    if (other == this) return true;
    if (!(other instanceof MyClass))return false;
    MyClass otherMyClass = (MyClass)other;
    ...test other properties here...
}

El uso de la anotación @Override 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 haces mal, obtendrás un error de compilación.

Otros consejos

Si usa eclipse simplemente vaya al menú superior

  

Fuente - > Generar iguales () y   hashCode ()

Ligeramente fuera de tema a su pregunta, pero probablemente valga la pena mencionarlo de todas formas:

Commons Lang tiene algunos métodos excelentes que puede utilizar para anular equals y hashcode. Consulte EqualsBuilder.reflectionEquals (...) y HashCodeBuilder.reflectionHashCode (...) . Me ahorró muchos dolores de cabeza en el pasado, aunque, por supuesto, si solo quieres hacer '' es igual a '' en ID puede no ajustarse a sus circunstancias.

También estoy de acuerdo en que debe usar la anotación @Override siempre que anule iguales (o cualquier otro método).

Otra solución rápida que ahorra código repetitivo es Anotación Lombok EqualsAndHashCode . Es fácil, elegante y personalizable. Y no depende del IDE . Por ejemplo;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{

    private long        errorNumber;
    private int         numberOfParameters;
    private Level       loggingLevel;
    private String      messageCode;

Vea las opciones disponibles para personalizar qué campos usar en los iguales. Lombok está disponible en maven . Simplemente agréguelo con proporcionado alcance:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>

en Android Studio es alt + insert --- > equals y hashCode

Ejemplo:

    @Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Proveedor proveedor = (Proveedor) o;

    return getId() == proveedor.getId();

}

@Override
public int hashCode() {
    return getId();
}

Considere:

Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...

la instrucción instanceOf se usa a menudo en la implementación de iguales.

¡Esta es una trampa popular!

El problema es que usar 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, ¡entonces el segundo igual devolverá falso!

si la clase considerada a la que pertenece ob1 se declara como final, entonces esto El problema no puede surgir, pero en general, debe probar lo siguiente:

this.getClass ()! = otherObject.getClass (); si no, devuelve falso, de lo contrario prueba los campos para comparar por igualdad!

recordId es propiedad del objeto

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Nai_record other = (Nai_record) obj;
        if (recordId == null) {
            if (other.recordId != null)
                return false;
        } else if (!recordId.equals(other.recordId))
            return false;
        return true;
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top