Domanda

Mi sono imbattuto in un problema interessante (e molto frustrante) con il metodo equals () che ha causato l'arresto anomalo di quella che pensavo fosse una classe ben collaudata e causava un errore che mi ha portato molto molto tempo per rintracciare.

Solo per completezza, non stavo usando un IDE o un debugger, solo un buon editor di testo vecchio stile e System.out's. Il tempo era molto limitato ed era un progetto scolastico.

Comunque -

Stavo sviluppando un carrello di base che poteva contenere un ArrayList di Book oggetti . Per implementare i metodi addBook () , removeBook () e hasBook () del carrello, volevo verificare se < code> Libro esisteva già nel Carrello . Quindi vado via -

public boolean equals(Book b) {
    ... // More code here - null checks
    if (b.getID() == this.getID()) return true;
    else return false;
}

Tutto funziona bene nei test. Creo 6 oggetti e li riempio di dati. Esegui molte operazioni di aggiunta, rimozione, esecuzione () sul Carrello e tutto funziona correttamente. Ho letto che puoi avere uguale a (TYPE var) o uguale a (Object o) {(CAST) var} ma ho ipotizzato che dal funzionava, non importava troppo.

Poi ho riscontrato un problema: dovevo creare un oggetto Book con solo l'ID all'interno della classe Book. Nessun altro dato verrebbe inserito al suo interno. Fondamentalmente il seguente:

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

All'improvviso, il metodo equals (Book b) non funziona più. Ci è voluto molto tempo per rintracciare senza un buon debugger e supponendo che la classe Carrello fosse stata testata e corretta correttamente. Dopo aver scambiato il metodo equals () nel modo seguente:

public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}

Tutto ha ripreso a funzionare. C'è una ragione per cui il metodo ha deciso di non prendere il parametro Book anche se chiaramente era un oggetto Book ? L'unica differenza sembrava essere stata istanziata all'interno della stessa classe e riempita con un solo membro di dati. Sono molto molto confuso. Per favore, fai luce?

È stato utile?

Soluzione

In Java, il metodo equals () ereditato da Object è:

public boolean equals(Object other);

In altre parole, il parametro deve essere di tipo Object .

L ' ArrayList utilizza il metodo equals corretto, in cui si chiamava sempre quello che non sostituiva correttamente gli equals di Object .

Non sovrascrivere correttamente il metodo può causare problemi.

Sovrascrivo equivale ogni volta a:

@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...
}

L'uso dell'annotazione @Override può aiutare moltissimo con errori sciocchi.

Usalo ogni volta che pensi di sovrascrivere un metodo di super classe o interfaccia. In questo modo, se sbagli, otterrai un errore di compilazione.

Altri suggerimenti

Se usi eclipse vai al menu principale

  

Fonte - > Genera equals () e   hashCode ()

Leggermente fuori tema per la tua domanda, ma probabilmente vale la pena menzionarlo comunque:

Commons Lang ha alcuni metodi eccellenti che puoi usare per sovrascrivere equals e hashcode. Dai un'occhiata a EqualsBuilder.reflectionEquals (...) e HashCodeBuilder.reflectionHashCode (...) . Mi hai risparmiato un sacco di mal di testa in passato, anche se ovviamente se vuoi solo fare "uguale a" su ID potrebbe non adattarsi alle tue circostanze.

Sono anche d'accordo che dovresti usare l'annotazione @Override ogni volta che esegui l'override di uguale (o qualsiasi altro metodo).

Un'altra soluzione rapida che consente di salvare il codice del bollettino è Lombok EqualsAndHashCode annotation . È facile, elegante e personalizzabile. E non dipende dall'IDE . Ad esempio;

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;

Consulta le opzioni disponibili per personalizzare i campi da utilizzare in uguali. Lombok è disponibile in maven . Basta aggiungerlo con fornito ambito:

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

in Android Studio è alt + inserisci --- > equals e hashCode

Esempio:

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

Si consideri:

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

l'istruzione instanceOf viene spesso utilizzata nell'implementazione di uguali.

Questa è una trappola popolare!

Il problema è che l'uso di instanceOf viola la regola della simmetria:

(object1.equals (object2) == true) if and only if (object2.equals (object1))

se il primo è uguale a true e object2 è un'istanza di una sottoclasse di la classe a cui appartiene obj1, quindi il secondo uguale restituirà false!

se la classe considerata a cui appartiene ob1 è dichiarata come definitiva, allora questa il problema non può sorgere, ma in generale, è necessario verificare come segue:

this.getClass ()! = otherObject.getClass (); in caso contrario, restituisce false, altrimenti prova i campi da confrontare per l'uguaglianza!

recordId è di proprietà dell'oggetto

@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;
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top