CodeGym/Blog Java/Random-FR/Comparer les comparaisons String et Equals en Java
Auteur
Milan Vucic
Programming Tutor at Codementor.io

Comparer les comparaisons String et Equals en Java

Publié dans le groupe Random-FR
membres
Salut! Aujourd'hui, nous allons parler d'un sujet très important et intéressant, à savoir la comparaison d'objets avec des objets (Compare Strings and Equals). Donc en Java, quand exactement l'objet A serait- il égal à l'objet B ? Essayons d'écrire un exemple :
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
Sortie de la console : false Attendez, arrêtez. Pourquoi est-ce que ces deux voitures ne sont pas égales ? Nous leur avons attribué les mêmes propriétés, mais le résultat de la comparaison est faux. La réponse est simple. L' opérateur == compare les références d'objet, pas les propriétés d'objet. Deux objets pourraient même avoir 500 champs avec des valeurs identiques, mais les comparer donnerait toujours faux. Après tout, les références car1 et car2pointer vers deux objets différents, c'est-à-dire vers deux adresses différentes. Imaginez une situation où vous comparez des gens. Certes, quelque part dans le monde, il y a une personne qui partage votre même nom, couleur des yeux, âge, taille, couleur des cheveux, etc. Cela vous rend similaire à bien des égards, mais vous n'êtes toujours pas des jumeaux - et vous ne l'êtes évidemment pas. la même personne.
Égaux et comparaisons de chaînes - 2
L' opérateur == utilise approximativement cette même logique lorsque nous l'utilisons pour comparer deux objets. Mais que se passe-t-il si vous avez besoin que votre programme utilise une logique différente ? Par exemple, supposons que votre programme effectue une analyse ADN. Il compare le code génétique de deux personnes et détermine s'il s'agit de jumeaux.
public class Man {

   int geneticCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.geneticCode = 1111222233;

       Man man2 = new Man();
       man2.geneticCode = 1111222233;

       System.out.println(man1 == man2);
   }
}
Sortie de la console : false Nous obtenons le même résultat logique (car nous n'avons pas beaucoup changé), mais maintenant cette logique n'est plus bonne ! Après tout, dans la vraie vie, l'analyse ADN devrait nous donner une garantie à 100 % que nous avons des jumeaux devant nous. Mais notre programme et l' opérateur == nous disent le contraire. Comment changer ce comportement et s'assurer que le programme produit le bon résultat lorsque l'ADN correspond ? Java a une méthode spéciale pour cela : equals() . Comme la méthode toString() , dont nous avons parlé précédemment, equals() appartient à la classe Object — la classe la plus importante de Java, la classe dont dérivent toutes les autres classes. Mais égal()ne change pas tout seul le comportement de notre programme :
public class Man {

   String geneticCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.geneticCode = "111122223333";

       Man man2 = new Man();
       man2.geneticCode = "111122223333";

       System.out.println(man1.equals(man2));
   }
}
Sortie console : false Exactement le même résultat, alors pourquoi avons-nous besoin de cette méthode ? :/ C'est tout simple. Le problème ici est que nous utilisons actuellement cette méthode telle qu'elle est implémentée dans la classe Object . Et si nous entrons dans le code de la classe Object et examinons l'implémentation de la méthode, voici ce que nous verrons :
public boolean equals(Object obj) {
   return (this == obj);
}
C'est la raison pour laquelle le comportement du programme n'a pas changé ! Le même opérateur == (qui compare les références) est utilisé dans la méthode equals() de la classe Object . Mais l'astuce avec cette méthode est que nous pouvons la remplacer. Remplacer signifie écrire votre propre méthode equals() dans notre classe Man , en lui donnant le comportement dont nous avons besoin ! À l'heure actuelle, nous n'aimons pas le fait que man1.equals(man2) soit essentiellement équivalent à man1 == man2 . Voici ce que nous ferons dans cette situation :
public class Man {

   int dnaCode;

   public boolean equals(Man man) {
       return this.dnaCode ==  man.dnaCode;

   }

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1.equals(man2));

   }
}
Sortie de la console : true Nous obtenons maintenant un résultat complètement différent ! En écrivant notre propre méthode equals() et en l'utilisant à la place de la méthode standard, nous avons produit le comportement correct : maintenant, si deux personnes ont le même ADN, le programme signale "l'analyse ADN a prouvé qu'ils sont jumeaux" et renvoie vrai ! En remplaçant la méthode equals() dans vos classes, vous pouvez facilement créer la logique de comparaison d'objets dont vous avez besoin. En fait, nous venons tout juste d'aborder la comparaison d'objets. Devant nous, il y a encore une grande leçon autonome sur ce sujet (vous la survolez maintenant si cela vous intéresse).

Comparer des chaînes en Java

Pourquoi considérons-nous les comparaisons de chaînes séparément de tout le reste ? La réalité est que les chaînes sont un sujet à part entière dans la programmation. Tout d'abord, si vous prenez tous les programmes Java jamais écrits, vous constaterez qu'environ 25 % des objets qu'ils contiennent sont des chaînes. Ce sujet est donc très important. Deuxièmement, le processus de comparaison des chaînes est vraiment très différent des autres objets. Prenons un exemple simple :
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Sortie console : false Mais pourquoi avons-nous obtenu false ? Après tout, les chaînes sont exactement les mêmes, mot pour mot :/ Vous avez peut-être deviné la raison : c'est parce que l' opérateur == compare les références ! Clairement, s1 et s2 ont des adresses différentes en mémoire. Si vous y avez pensé, retravaillons notre exemple :
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       System.out.println(s1 == s2);
   }
}
Maintenant, nous avons à nouveau deux références, mais le résultat est exactement le contraire : Sortie console : true Impuissant confus ? Découvrons ce qui se passe. L' opérateur == compare vraiment les adresses mémoire. C'est toujours vrai et vous n'avez pas besoin d'en douter. Cela signifie que si s1 == s2 renvoie vrai, alors ces deux chaînes ont la même adresse. Et en effet c'est vrai ! Il est temps de vous présenter une zone spéciale de la mémoire pour le stockage des chaînes : le pool de chaînes
Égaux et comparaisons de chaînes - 3
Le pool de chaînes est une zone de stockage de toutes les valeurs de chaîne que vous créez dans votre programme. Pourquoi a-t-il été créé ? Comme nous l'avons dit précédemment, les chaînes représentent un pourcentage énorme de tous les objets. Tout programme volumineux crée beaucoup de chaînes. Le pool de chaînes a été créé pour économiser de la mémoire : les chaînes y sont placées, puis les chaînes créées par la suite font référence à la même zone de mémoire - il n'est pas nécessaire d'allouer de la mémoire supplémentaire à chaque fois. Chaque fois que vous écrivez String = "........", le programme vérifie s'il existe une chaîne identique dans le pool de chaînes. Si c'est le cas, aucune nouvelle chaîne ne sera créée. Et la nouvelle référence pointera vers la même adresse dans le pool de chaînes (où se trouve la chaîne identique). Alors, quand nous avons écrit
String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 pointe au même endroit que s1 . La première instruction crée une nouvelle chaîne dans le pool de chaînes. La deuxième instruction fait simplement référence à la même zone de mémoire que s1 . Vous pourriez créer 500 autres chaînes identiques et le résultat ne changerait pas. Attendez une minute. Si c'est vrai, alors pourquoi cet exemple n'a-t-il pas fonctionné auparavant ?
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Je pense que votre intuition vous a déjà dit la raison =) Essayez de deviner avant de lire plus loin. Vous pouvez voir que ces deux chaînes ont été déclarées de différentes manières. L'un avec le nouvel opérateur et l'autre sans. C'est là que réside la raison. Lorsque l' opérateur new est utilisé pour créer un objet, il alloue de force une nouvelle zone de mémoire pour l'objet. Et une chaîne créée à l'aide de new ne se retrouve pas dans le pool de chaînes — elle devient un objet séparé, même si son texte correspond parfaitement à une chaîne du pool de chaînes. Autrement dit, si nous écrivons le code suivant :
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       String s3 = new String("CodeGym is the best website for learning Java!");
   }
}
En mémoire, ça ressemble à ça :
Égaux et comparaisons de chaînes - 4
Et chaque fois que vous créez un nouvel objet en utilisant new , une nouvelle zone de mémoire est allouée, même si le texte à l'intérieur de la nouvelle chaîne est le même ! Il semble que nous ayons compris l' opérateur == . Mais qu'en est-il de notre nouvelle connaissance, la méthode equals() ?
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1.equals(s2));
   }
}
Sortie console : vrai Intéressant. Nous sommes certains que s1 et s2 pointent vers des zones différentes de la mémoire. Mais la méthode equals () nous dit toujours qu'ils sont égaux. Pourquoi? N'oubliez pas que nous avons déjà dit que la méthode equals () pouvait être remplacée pour comparer des objets comme nous le voulions ? C'est exactement ce qu'ils ont fait avec la classe String . Il remplace le equals ()méthode. Et au lieu de comparer les références, il compare la séquence de caractères dans les chaînes. Si le texte est le même, peu importe comment il a été créé ou où il est stocké : que ce soit dans le pool de chaînes ou dans une zone de mémoire distincte. Le résultat de la comparaison sera vrai. Soit dit en passant, Java vous permet d'effectuer des comparaisons de chaînes insensibles à la casse. Normalement, si l'une des chaînes ne contient que des lettres majuscules, le résultat de la comparaison sera faux :
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CODEGYM IS THE BEST WEBSITE FOR LEARNING JAVA!");
       System.out.println(s1.equals(s2));
   }
}
Sortie console : false Pour les comparaisons insensibles à la casse, la classe String a la méthode equalsIgnoreCase() . Vous pouvez l'utiliser si vous vous souciez uniquement de comparer la séquence de caractères spécifiques plutôt que la casse des lettres. Par exemple, cela peut être utile lors de la comparaison de deux adresses :
public class Main {

   public static void main(String[] args) {

       String address1 = "2311 Broadway Street, San Francisco";
       String address2 = new String("2311 BROADWAY STREET, SAN FRANCISCO");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
Dans ce cas, nous parlons évidemment de la même adresse, il est donc logique d'utiliser la méthode equalsIgnoreCase() .

La méthode String.intern()

La classe String a une autre méthode délicate : interne() ; La méthode intern() fonctionne directement avec le pool de chaînes. Si vous appelez la méthode intern() sur une chaîne :
  • Il vérifie s'il existe une chaîne correspondante dans le pool de chaînes
  • Si c'est le cas, il renvoie la référence à la chaîne dans le pool
  • Si ce n'est pas le cas, il ajoute la chaîne au pool de chaînes et lui renvoie une référence.
Après avoir utilisé la méthode intern() sur une référence de chaîne obtenue à l'aide de new , nous pouvons utiliser l' opérateur == pour la comparer avec une référence de chaîne du pool de chaînes.
public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2.intern());
   }
}
Sortie de la console : true Lorsque nous avons comparé ces chaînes précédemment sans intern() , le résultat était faux. Maintenant, la méthode intern() vérifie si la chaîne "CodeGym est le meilleur site pour apprendre Java !" est dans le pool de chaînes. Bien sûr, c'est le cas : nous l'avons créé avec
String s1 = "CodeGym is the best website for learning Java!";
Nous vérifions si le s1 et la référence renvoyée par s2.intern() pointent vers la même zone de mémoire. Et bien sûr, ils le font :) En résumé, mémorisez et appliquez cette règle importante : utilisez TOUJOURS la méthode equals() pour comparer des chaînes ! Lorsque nous comparons des chaînes, nous entendons presque toujours comparer leurs caractères plutôt que des références, des zones de mémoire ou quoi que ce soit d'autre. La méthode equals() fait exactement ce dont vous avez besoin. Pour renforcer ce que vous avez appris, nous vous suggérons de regarder une leçon vidéo de notre cours Java

Plus de lecture :

Commentaires
  • Populaires
  • Nouveau
  • Anciennes
Tu dois être connecté(e) pour laisser un commentaire
Cette page ne comporte pas encore de commentaires