Outrepasser la méthode java equals () - ne fonctionne pas?

j'ai rencontré un problème intéressant (et très frustrant) avec la méthode equals() aujourd'hui qui a causé ce que je pensais être une classe bien testée de planter et de causer un bug qui m'a pris un très long temps à traquer.

juste pour être complet, je n'utilisais pas un IDE ou un débogueur - juste un bon éditeur de texte à l'ancienne et un système.dehors. Le temps était très limité et c'était un projet scolaire.

anywhere -

j'ai été développer un panier d'achat de base qui pourrait contenir un ArrayList de Book objets . Afin de mettre en œuvre les méthodes addBook() , removeBook() , et hasBook() du chariot, je voulais vérifier si le Book existait déjà dans le Cart . Donc, je vais -

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

Tout fonctionne très bien dans les tests. Je crée 6 objets et je les remplis de données. Faire beaucoup de ajoute, supprime, a() les opérations sur la Cart et tout fonctionne très bien. J'ai lu que vous pouvez soit avoir equals(TYPE var) ou equals(Object o) { (CAST) var } mais supposé que depuis qu'il fonctionnait, il n'a pas trop d'importance.

puis j'ai rencontré un problème - j'ai dû créer un Book objet avec seulement le ID dans lui de l'intérieur de la classe de Livre. Aucune autre donnée ne serait entrée. Essentiellement le suivant:

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

Tout d'un coup, la méthode equals(Book b) ne fonctionne plus. Il a fallu beaucoup de temps pour le retrouver sans un bon Débogueur et en supposant que la classe Cart était correctement testée et correcte. Après avoir remplacé la méthode equals() par la suivante:

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

Tout a commencé à travailler à nouveau. Y a-t-il une raison pour laquelle la méthode a décidé de ne pas prendre le paramètre de livre, bien qu'il soit clairement était a Book objet? La seule différence semble être a été instancié à l'intérieur de la même classe, et rempli seulement avec un membre de données. Je suis très très confus. S'il vous plaît, jeter un peu de lumière?

143
demandé sur RobAu 2008-10-09 08:22:57

8 réponses

en Java, la méthode equals() héritée de Object est:

public boolean equals(Object other);

en d'autres termes, le paramètre doit être du type Object .

le ArrayList utilise la méthode correcte des égaux, où vous appeliez toujours celui qui n'a pas correctement outrepassé les égaux de Object .

ne pas dépasser la méthode correctement peut causer des problèmes.

I override égale le à chaque fois:

@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'utilisation de l'annotation @Override peut aider une tonne avec des erreurs stupides.

utilisez-le chaque fois que vous pensez que vous supplantez une classe super' ou la méthode de l'interface. De cette façon, si vous le faites mal, vous obtiendrez une erreur de compilation.

311
répondu jjnguy 2014-06-06 19:02:20

si vous utilisez eclipse, allez dans le menu du haut

Source --> Générer equals() et hashCode ()

101
répondu Fred 2011-06-02 16:15:43

légèrement hors sujet à votre question, mais il est probablement intéressant de mentionner de toute façon:

Commons Lang a d'excellentes méthodes que vous pouvez utiliser dans overrading equals et hashcode. Découvrez EqualsBuilder.réflectionequals(...) et HashCodeBuilder.reflectionHashCode(...) . Ça m'a épargné beaucoup de maux de tête dans le passé-même si bien sûr si vous voulez juste faire "égal" sur ID il se peut que cela ne rentre pas vos circonstances.

je suis également d'accord que vous devez utiliser l'annotation @Override chaque fois que vous êtes supérieur égal (ou toute autre méthode).

11
répondu 2008-10-09 08:27:54

une autre solution rapide qui sauve le code boilerplate est . Il est facile, élégant et personnalisable. Et ne dépend pas de L'IDE . Par exemple:

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;

voir les options disponibles pour personnaliser les champs à utiliser dans les égaux. Lombok est disponible en maven . Il suffit de l'ajouter avec fourni champ d'application:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>
4
répondu borjab 2014-10-17 11:24:19

dans Android Studio est alt + insert - - - - > égale et hashCode

exemple:

    @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();
}
1
répondu David Hackro 2015-08-22 05:44:26

prendre en considération:

Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
1
répondu bcsb1001 2015-09-09 19:38:21

l'énoncé instanceOf est souvent utilisé dans la mise en œuvre d'égaux.

c'est un piège populaire !

Le problème est que l'utilisation de instanceOf viole la règle de symétrie:

(object1.equals(object2) == true) si et seulement si (object2.equals(object1))

si le premier égal est vrai, et l'object2 est une instance d'une sous-classe de la classe où obj1 appartient, alors la seconde égale return false!

si la classe considérée dans laquelle ob1 appartient est déclarée comme définitive, cette le problème ne peut pas se poser, mais en général, vous devriez tester comme suit:

this.getClass() != otherObject.getClass(); sinon, retourne false, sinon le test les champs de comparer pour l'égalité!

0
répondu Nikel8000 2015-08-13 22:26:40

recordId est la propriété de l'objet

@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;
    }
-1
répondu vootla561 2015-08-24 12:16:49