Java Challengers # 2: comparaison de chaînes
Comme toujours, nous avons beaucoup de retard pour le début du cours, donc hier a eu lieu une deuxième leçon parmi le nouveau thread "Java Developer" . Mais il en est ainsi, petites choses dans la vie, mais pour l'instant nous continuons à publier une série d'articles sur Java Challengers, dont la traduction a été préparée pour vous.
En Java, la classe String
encapsule un tableau de caractères ( note du traducteur - avec java 9, il s'agit déjà d'un tableau d' byte
, voir Chaînes compactes en Java 9 ). En termes simples, String
est un tableau de caractères utilisé pour composer des mots, des phrases ou d'autres constructions.
L'encapsulation est l'un des concepts les plus puissants de la programmation orientée objet. Grâce à l'encapsulation, vous n'avez pas besoin de savoir comment fonctionne la classe String
. Il vous suffit de connaître les méthodes de son interface.

Lorsque vous regardez la classe String
en Java, vous pouvez voir comment le tableau char
est encapsulé:
public String(char value[]) { this(value, 0, value.length, null); }
Pour mieux comprendre l'encapsulation, imaginez un objet physique: une machine. Avez-vous besoin de savoir comment fonctionne une voiture sous le capot pour la conduire? Bien sûr que non, mais vous devez savoir ce que font les interfaces de la voiture: la pédale d'accélérateur, les freins et le volant. Chacune de ces interfaces prend en charge certaines actions: accélération, freinage, tourner à gauche, tourner à droite. La même chose est vraie dans la programmation orientée objet.
Le premier article de la série Java Challengers portait sur la surcharge de méthode, qui est largement utilisée dans la classe String
. La surcharge peut rendre vos cours vraiment flexibles:
public String(String original) {} public String(char value[], int offset, int count) {} public String(int[] codePoints, int offset, int count) {} public String(byte bytes[], int offset, int length, String charsetName) {}
Au lieu d'essayer de comprendre le fonctionnement de la classe String
, cet article vous aidera à comprendre ce qu'elle fait et comment l' utiliser dans votre code.
Qu'est-ce qu'un pool de chaînes?
La classe String
est sans doute la classe la plus couramment utilisée en Java. Si nous créons un nouvel objet dans la mémoire dynamique (tas de mémoire) à chaque fois que nous utilisons String
, alors nous gaspillerons beaucoup de mémoire. Le pool de chaînes résout ce problème en stockant un seul objet pour chaque valeur de ligne.

Lignes dans un pool de lignes
Bien que nous ayons créé plusieurs variables String
avec les valeurs Duke
et Juggy
, seuls deux objets sont créés et stockés dans la mémoire dynamique (tas). Voir l'exemple de code suivant pour la preuve. (Rappelez-vous qu'en Java, l'opérateur " ==
" est utilisé pour comparer deux objets et déterminer si le même objet est le même ou non.)
String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy);
Ce code renverra true
car les deux variables String
pointent vers le même objet dans le pool de chaînes. Leurs significations sont les mêmes.
L'exception est le new
opérateur.
Regardez maintenant ce code - il ressemble à l'exemple précédent, mais il y a une différence.
String duke = new String("duke"); String anotherDuke = new String("duke"); System.out.println(duke == anotherDuke);
Sur la base de l'exemple précédent, vous pourriez penser que ce code retournera true
, mais ce n'est pas le cas. L'ajout d'un new
opérateur crée un nouvel objet String
en mémoire. Ainsi, la JVM créera deux objets différents.
Méthodes natives
Les méthodes natives en Java sont des méthodes qui seront compilées à l'aide du langage C, généralement dans le but de gérer la mémoire et d'optimiser les performances.
Pools de chaînes et méthode intern()
Pour stocker des chaînes dans un pool, une méthode appelée internalisation des chaînes est utilisée.
Voici ce que Javadoc nous dit sur la méthode intern()
:
public native String intern();
La méthode intern()
est utilisée pour stocker des chaînes dans un pool de chaînes. Tout d'abord, il vérifie si une ligne déjà créée existe dans le pool. Sinon, il crée une nouvelle ligne dans le pool. La logique du pool de lignes est basée sur le modèle Flyweight .
Maintenant, remarquez ce qui se passe lorsque nous utilisons new
pour créer deux lignes:
String duke = new String("duke"); String duke2 = new String("duke"); System.out.println(duke == duke2);
Contrairement à l'exemple précédent avec le new
mot-clé, dans ce cas, la comparaison retournera true
. En effet, l'utilisation de la méthode intern()
garantit que la chaîne se trouve dans le pool.
Méthode equals
dans la classe String
La méthode equals()
est utilisée pour vérifier si deux classes sont identiques ou non. Puisque equals()
se trouve dans la classe Object
, chaque classe Java en hérite. Mais la méthode equals()
doit être remplacée pour qu'elle fonctionne correctement. Bien sûr, String
remplace equals()
.
Jetez un oeil:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (coder() == aString.coder()) { return isLatin1() ? StringLatin1.equals(value, aString.value) : StringUTF16.equals(value, aString.value); } } return false; }
Comme vous pouvez le voir, la valeur de la classe String
est comparée via equals()
et non via une référence d'objet. Peu importe que les références aux objets soient différentes; les conditions seront comparées.
Méthodes de String
courantes
Il y a encore une chose que vous devez savoir avant de résoudre le problème de comparaison de chaînes.
Considérez les méthodes les plus courantes de la classe String
:
Résoudre le problème de comparaison de chaînes
Vérifions ce que vous avez appris sur la classe String
en résolvant un petit casse-tête.
Dans cette tâche, vous comparez plusieurs lignes à l'aide des concepts que vous avez appris. En regardant le code ci-dessous, pouvez-vous déterminer la valeur de chaque result
variable?
public class ComparisonStringChallenge { public static void main(String... doYourBest) { String result = ""; result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; result += "flexibleCode" == "flexibleCode" ? "2" : "3"; result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; System.out.println(result); } }
Quelle sera la conclusion?
- A: 02468
- B: 12469
- C: 12579
- D: 12568
La bonne réponse est donnée à la fin de l'article.
Que s'est-il passé maintenant? Comprendre le comportement des String
Dans la première ligne, nous voyons:
result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1";
Dans ce cas, le résultat est false
, car lorsque la méthode trim()
supprime des espaces, elle crée une nouvelle String
à l'aide du new
opérateur.
Ensuite, nous voyons:
result += "flexibleCode" == "flexibleCode" ? "2" : "3";
Il n'y a pas de secret ici, les lignes sont les mêmes dans le pool de lignes. Cette comparaison renvoie true
.
Ensuite, nous avons:
result += new String("doYourBest") == new String("doYourBest") ? "4" : "5";
L'utilisation de new
conduit à la création de deux nouvelles lignes et peu importe que leurs valeurs soient égales ou non. Dans ce cas, la comparaison sera false
même si les valeurs sont les mêmes.
Suivant:
result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7";
Puisque nous avons utilisé la méthode equals()
, la valeur de la chaîne sera comparée, pas l'instance de l'objet.
Dans ce cas, peu importe qu'il s'agisse d'objets différents ou non, car la valeur est comparée. Le résultat est true
.
Enfin, nous avons:
result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9";
Comme vous l'avez vu précédemment, la méthode intern()
place une chaîne dans un pool de chaînes. Les deux lignes pointent vers le même objet, donc dans ce cas true
.
Erreurs de chaîne courantes
Il peut être difficile de déterminer si deux lignes pointent vers le même objet ou non, surtout lorsque les lignes contiennent la même valeur. Il est utile de se rappeler que l'utilisation de new
conduit toujours à la création d'un nouvel objet en mémoire, même si les valeurs de chaîne sont les mêmes.
L'utilisation de méthodes String
pour comparer les références d'objets peut également être délicate. La particularité est que si la méthode change quelque chose dans la ligne, alors il y aura différentes références aux objets.
Quelques exemples pour clarifier:
System.out.println("duke".trim() == "duke".trim());
Cette comparaison sera vraie car la méthode trim()
ne crée pas de nouvelle ligne.
System.out.println(" duke".trim() == "duke".trim());
Dans ce cas, la première méthode trim()
génère une nouvelle ligne, car la méthode fera son travail et donc les liens seront différents.
Enfin, lorsque trim()
fait son travail, il crée une nouvelle ligne:
À retenir des cordes
Les lignes ne sont pas modifiables, leur état ne peut donc pas être modifié.
Pour économiser de la mémoire, la JVM stocke les chaînes dans un pool de chaînes. Lors de la création d'une nouvelle ligne, la JVM vérifie sa valeur et pointe vers un objet existant. Si le pool n'a pas de ligne avec cette valeur, la machine virtuelle Java crée une nouvelle ligne.
L'opérateur " ==
" compare les références d'objets. La méthode equals()
compare les valeurs de chaîne. La même règle s'appliquera à tous les objets.
Lorsque vous utilisez le new
opérateur, une nouvelle ligne sera créée dans le tas (Note du traducteur - il est écrit dans l'original qu'il se trouve dans le pool, mais ce n'est pas le cas, merci zagayevskiy ), même s'il existe une ligne avec la même valeur.
La réponse
La réponse à ce problème est D. La conclusion sera 12568.
À suivre ...