2 votes

Pourquoi la comparaison d'objet Java échoue-t-elle avec les méthodes '==' et .equals() ?

Je compare les mêmes objets en utilisant les méthodes == et equals(), mais les deux ne fonctionnent pas. J'ai essayé quatre combinaisons comme suit. S'il vous plaît guidez-moi si je fais une erreur.

public class Question {

int rollNo;
String name;

Question(int rollNo, String name) {
    this.rollNo = new Integer(rollNo);
    this.name = new String(name);
}

public int getRollNo() {
    return new Integer(rollNo);
}

public void setRollNo(int rollNo) {
    if(rollNo>0) this.rollNo = rollNo;
}

public String getName() {
    return new String(name);
}

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

public static void main(String[] args) {
    Question obj1 = new Question(123, "Student1");
    Question obj2 = new Question(123, "Student1");
    Question obj3 = new Question(456, "Student2");

            // Toutes les conditions if évaluent à false
    if(obj1 == obj2) System.out.println("Objets 1 et 2 égaux en utilisant ==");
    if(obj1.equals(obj2)) System.out.println("Objets 1 et 2 égaux en utilisant equals()");
    if(obj1 == new Question(123, "Student1")) System.out.println("Objets 1 et 2 égaux en utilisant == et new");
    if((new Question(123, "Student1")).equals(obj2)) System.out.println("Objets 1 et 2 égaux en utilisant equals() et new");        
}

}

Je suis ouvert aux suggestions sur la qualité de mon code car je viens de commencer à coder.

2voto

Stephen C Points 255558

Il échoue avec == car les objets Question sont des objets différents. (L'opérateur == pour les types de référence teste si les références sont pour le même objet.)

Il échoue avec equals parce que vous utilisez la méthode Object::equals(Object). Cette méthode est spécifiée pour avoir la même signification que ==.

Si vous voulez que Question::equals(Object) se comporte différemment, vous devez remplacer la méthode héritée de Object en ajoutant une méthode comme ceci :

    @Override
    public boolean equals(Object other) {
        // implémentez cela selon les spécifications pour donner l'égalité
        // sémantique dont vous avez besoin
    }

Une implémentation réelle pourrait ressembler à ceci :

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof Question) {
            Question other = (Question) obj;
            return this.rollNo == other.rollNo &&
                   this.name.equals(other.name);
        } else {
            return false;
        }
    }

J'ai remarqué quelques autres problèmes dans votre code. Par exemple :

    Question(int rollNo, String name) {
        this.rollNo = new Integer(rollNo);
        this.name = new String(name);
    }
  1. Le constructeur devrait probablement être public.
  2. Étant donné que this.rollNo est déclaré comme un int, créer un Integer et l'assigner est inutile... et inefficace. Ce qui se passera est que l'Integer sera déballé pour obtenir sa valeur, et l'objet sera ensuite jeté. Il suffit d'assigner rollNo à this.rollNo.
  3. Si vous avez vraiment besoin d'obtenir une instance Integer explicitement, la manière correcte de le faire est d'utiliser Integer.valueOf(int). Cela utilise un cache intégré d'objets Integer.
  4. Créer une chaîne de caractères avec new String(name) est inutile et inefficace. Les chaînes de caractères sont immuables. Il n'est pas nécessaire de les copier. Surtout pas ici.

1voto

Matt U Points 3917

Une classe est un type de référence, donc lors de la vérification de l'égalité, elle sera fausse chaque fois que vous ne comparez pas deux références au même objet. Toutes les valeurs des objets peuvent être les mêmes, mais ils ne sont pas le même objet.

Si vous souhaitez pouvoir comparer deux instances de votre classe Question de cette manière, vous devrez remplacer les méthodes equals et getHashCode. Voir ici: https://www.geeksforgeeks.org/overriding-equals-method-in-java/

1voto

Sharad Nanda Points 1029

Vos objets obj1 et obj2 pourraient être considérés comme similaires en raison des mêmes valeurs de chaque variable d'instance, mais ils ne sont pas égaux. Chacun de ces objets est stocké en mémoire Heap et possède un identifiant unique (que vous pouvez vérifier dans le mode de débogage de votre IDE (Eclipse, Intellij, etc.)).

1. Pourquoi '==' est faux dans vos conditions

Dans toutes vos déclarations if où vous utilisez l'opérateur '==', les références sont vérifiées et dans chaque cas, les références sont dirigées vers des objets différents (comme expliqué ci-dessus), donc vos conditions s'évaluent à faux.

2. Pourquoi equals() renvoie également faux dans votre condition

Dans vos autres déclarations if, vous utilisez essentiellement l'implémentation par défaut de equals() où le compilateur vérifie votre objet par rapport à ce mot-clé (qui est la référence sur laquelle vous avez appelé la méthode equals). Par conséquent, il se comporte comme '==' et vous renvoie faux pour la même raison.

Que peut-on faire pour surmonter cela?

Je suppose que votre cas d'utilisation exige que les objets soient traités comme égaux s'ils ont la même valeur pour les variables d'instance, donc vous devez implémenter cette logique dans votre méthode equals en la redéfinissant. Chaque fois que vous voulez comparer vos objets personnalisés, il est fortement recommandé de remplacer la méthode equals() et hashCode() (car des objets égaux doivent générer le même hachage, vous devez donc en tenir compte de manière appropriée dans votre code).

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