125 votes

Comment surcharger la méthode equals en Java

J'essaie de remplacer la méthode equals en Java. J'ai une classe People qui comporte essentiellement 2 champs de données name et age . Maintenant, je veux remplacer equals pour que je puisse vérifier entre 2 objets People.

Mon code est le suivant

public boolean equals(People other){
    boolean result;
    if((other == null) || (getClass() != other.getClass())){
        result = false;
    } // end if
    else{
        People otherPeople = (People)other;
        result = name.equals(other.name) &&  age.equals(other.age);
    } // end else

    return result;
} // end equals

Mais quand j'écris age.equals(other.age) Cela me donne une erreur car la méthode equals ne peut comparer que des String et age est un Integer.

Solution

J'ai utilisé == opérateur comme suggéré et mon problème est résolu.

143voto

Kim Points 1534
//Written by K@stackoverflow
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        ArrayList<Person> people = new ArrayList<Person>();
        people.add(new Person("Subash Adhikari", 28));
        people.add(new Person("K", 28));
        people.add(new Person("StackOverflow", 4));
        people.add(new Person("Subash Adhikari", 28));

        for (int i = 0; i < people.size() - 1; i++) {
            for (int y = i + 1; y <= people.size() - 1; y++) {
                boolean check = people.get(i).equals(people.get(y));

                System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
                System.out.println(check);
            }
        }
    }
}

//written by K@stackoverflow
public class Person {
    private String name;
    private int age;

    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }

        if (obj.getClass() != this.getClass()) {
            return false;
        }

        final Person other = (Person) obj;
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }

        if (this.age != other.age) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
        hash = 53 * hash + this.age;
        return hash;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Sortie :

courir :

-- Subash Adhikari - VS - K faux

-- Subash Adhikari - VS - StackOverflow faux

-- Subash Adhikari - VS - Subash Adhikari vrai

-- K - VS - StackOverflow faux

-- K - VS - Subash Adhikari faux

-- StackOverflow - VS - Subash Adhikari faux

-- BUILD SUCCESSFUL (temps total : 0 secondes)

26voto

fortran Points 26495

L'introduction d'une nouvelle signature de méthode qui change les types de paramètres est appelée surcharge :

public boolean equals(People other){

Ici People est différent de Object .

Lorsqu'une signature de méthode reste identique à celle de sa superclasse, elle est appelée Remplacement de et le @Override permet de distinguer les deux au moment de la compilation :

@Override
public boolean equals(Object other){

Sans voir la déclaration réelle de age il est difficile de dire pourquoi l'erreur apparaît.

19voto

Adrian Mouat Points 5533

Je ne suis pas sûr des détails car vous n'avez pas posté tout le code, mais.. :

  • n'oubliez pas de passer outre hashCode() également
  • le site equals devrait avoir Object pas People comme type d'argument. Pour l'instant, vous surchargez, et non pas surchargez, la méthode equals, ce qui n'est probablement pas ce que vous voulez, surtout que vous vérifiez son type plus tard.
  • vous pouvez utiliser instanceof pour vérifier qu'il s'agit d'un objet du peuple, par ex. if (!(other instanceof People)) { result = false;}
  • equals est utilisé pour tous les objets, mais pas pour les primitives. Je pense que vous voulez dire que age est un int (primitif), dans ce cas, utilisez simplement == . Notez qu'un Integer (avec un 'I' majuscule) est un objet qui doit être comparé avec des égaux.

Voir Quelles sont les questions à prendre en compte lors du remplacement de equals et hashCode en Java ? pour plus de détails.

14voto

Point 10 : Respecter le contrat général en cas de dérogation aux égalités.

D'après Effective Java , Remplacement de la equals Cette méthode semble simple, mais il existe de nombreuses façons de se tromper, et les conséquences peuvent être désastreuses. Le moyen le plus simple d'éviter les problèmes est de ne pas surcharger la méthode equals dans ce cas, chaque instance de la classe n'est égale qu'à elle-même. C'est la bonne chose à faire si l'une des conditions suivantes s'applique :

  • Chaque instance de la classe est intrinsèquement unique . Ceci est vrai pour les classes telles que Thread qui représentent des entités actives plutôt que des valeurs. L'implémentation de equals fournie par Object a exactement le bon comportement pour ces classes.

  • Il n'est pas nécessaire que la classe fournisse un test d'"égalité logique". Par exemple, java.util.regex.Pattern aurait pu surcharger equals pour vérifier si deux instances de Pattern représentaient exactement la même expression régulière, mais les concepteurs ne pensaient pas que les clients auraient besoin ou voudraient cette fonctionnalité. Dans ces circonstances, l'implémentation equals héritée d'Object est idéale.

  • Une superclasse a déjà surchargé equals, et le comportement de la superclasse est approprié pour cette classe. Par exemple, la plupart des implémentations Set héritent leur implémentation equals de AbstractSet, les implémentations List de AbstractList, et les implémentations Map de AbstractMap.

  • La classe est privée ou privée par paquet et vous êtes certain que sa méthode equals ne sera jamais invoquée. Si vous êtes extrêmement prudent, vous pouvez remplacer la méthode equals pour vous assurer qu'elle ne sera pas invoquée accidentellement :

Le site equals implémente une relation d'équivalence. Elle possède ces propriétés :

  • Réflexif : Pour toute valeur de référence non nulle x , x.equals(x) doit retourner vrai.

  • Symétrique : Pour toute valeur de référence non nulle x et y , x.equals(y) doit retourner vrai si et seulement si y.equals(x) retourne vrai.

  • Transitif : Pour toute valeur de référence non nulle x , y , z si x.equals(y) renvoie à true et y.equals(z) renvoie à true alors x.equals(z) doit retourner true .

  • Cohérent : Pour toutes les valeurs de référence non nulles x et y , les invocations multiples de x.equals(y) doit systématiquement retourner true ou retourner systématiquement false à condition qu'aucune information utilisée dans les comparaisons d'équivalents ne soit modifiée.

  • Pour toute valeur de référence non nulle x , x.equals(null) doit retourner false .

Voici une recette pour une méthode d'égalisation de haute qualité :

  1. Utilisez le == pour vérifier si l'argument est une référence à cet objet. Si c'est le cas, il renvoie true. Il s'agit simplement d'une optimisation des performances, mais qui vaut la peine d'être effectuée si la comparaison est potentiellement coûteuse.

  2. Utilisez le instanceof pour vérifier si l'argument a le bon type. Si ce n'est pas le cas, il renvoie false. Typiquement, le type correct est la classe dans laquelle la méthode se produit. Parfois, il s'agit d'une interface implémentée par cette classe. Utilisez une interface si la classe implémente une interface qui affine le contrat equals pour permettre des comparaisons entre les classes qui implémentent l'interface. Les interfaces de collection telles que Set, List, Map et Map.Entry possèdent cette propriété.

  3. Transférer l'argument vers le type correct. Comme ce cast a été précédé d'un test instanceof, son succès est garanti.

  4. Pour chaque champ "significatif" de la classe, vérifier si ce champ de l'argument correspond au champ correspondant de cet objet. Si tous ces tests réussissent, retournez true ; sinon, retournez false. Si le type de l'étape 2 est une interface, vous devez accéder aux champs de l'argument via les méthodes de l'interface. Si le type est une classe, vous pouvez accéder directement aux champs, en fonction de leur accessibilité.

  5. Pour les champs primitifs dont le type n'est pas float ou double utilisez le == pour les comparaisons ; pour les champs de référence d'objet, appelez l'opérateur equals de manière récursive ; pour float utilisez les champs statiques Float.compare(float, float) et pour double les champs, utilisez Double.compare(double, double) . Le traitement particulier des champs flottants et doubles est rendu nécessaire par l'existence de Float.NaN , -0.0f et les valeurs doubles analogues ; alors que vous pourriez comparer float et double avec les méthodes statiques Float.equals et Double.equals cela impliquerait d'effectuer un autocontrôle sur chaque comparaison, ce qui aurait des performances médiocres. Pour array champs, appliquez ces directives à chaque élément. Si chaque élément d'un champ de tableau est significatif, utilisez l'une des méthodes suivantes Arrays.equals méthodes.

  6. Certains champs de référence d'objet peuvent légitimement contenir null . Pour éviter la possibilité d'un NullPointerException pour vérifier l'égalité de ces champs à l'aide de la méthode statique Objects.equals(Object, Object) .

    // Class with a typical equals method
    
    public final class PhoneNumber {
    
        private final short areaCode, prefix, lineNum;
    
        public PhoneNumber(int areaCode, int prefix, int lineNum) {
    
            this.areaCode = rangeCheck(areaCode,  999, "area code");
    
            this.prefix   = rangeCheck(prefix,    999, "prefix");
    
            this.lineNum  = rangeCheck(lineNum,  9999, "line num");
    
        }
    
        private static short rangeCheck(int val, int max, String arg) {
    
            if (val < 0 || val > max)
    
               throw new IllegalArgumentException(arg + ": " + val);
    
            return (short) val;
    
        }
    
        @Override public boolean equals(Object o) {
            if (o == this)
                return true;
            if (!(o instanceof PhoneNumber))
                return false;
            PhoneNumber pn = (PhoneNumber)o;
            return pn.lineNum == lineNum && pn.prefix == prefix
                    && pn.areaCode == areaCode;
        }
        ... // Remainder omitted
    
    }

12voto

NeverJr Points 297
@Override
public boolean equals(Object that){
  if(this == that) return true;//if both of them points the same address in memory

  if(!(that instanceof People)) return false; // if "that" is not a People or a childclass

  People thatPeople = (People)that; // than we can cast it to People safely

  return this.name.equals(thatPeople.name) && this.age == thatPeople.age;// if they have the same name and same age, then the 2 objects are equal unless they're pointing to different memory adresses
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X