Comparaisons de chaînes en Java
En Java, la String
classe encapsule un tableau de char
. En termes simples, String
un tableau de caractères est utilisé pour composer des mots, des phrases ou toute autre donnée souhaitée.
L'encapsulation est l'un des concepts les plus puissants de la programmation orientée objet. En raison de l'encapsulation, vous n'avez pas besoin de savoir comment fonctionne la classe String; vous avez juste besoin de savoir quelles méthodes utiliser sur son interface.
Lorsque vous regardez la String
classe en Java, vous pouvez voir comment le tableau de char
est encapsulé:
public String(char value[]) { this(value, 0, value.length, null); }
Pour mieux comprendre l'encapsulation, considérez un objet physique: une voiture. Avez-vous besoin de savoir comment fonctionne la voiture sous le capot pour la conduire? Bien sûr que non, mais vous devez savoir ce que font les interfaces de la voiture: des choses comme l'accélérateur, les freins et le volant. Chacune de ces interfaces supporte certaines actions: accélérer, freiner, tourner à gauche, tourner à droite. C'est la même chose dans la programmation orientée objet.
Mon premier blog de la série Java Challengers a introduit la surcharge de méthode, une technique que la String
classe utilise largement. La surcharge peut rendre vos cours vraiment flexibles, notamment String
:
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) {} // And so on…...
Plutôt que d'essayer de comprendre le fonctionnement de la String
classe, ce Java Challenger vous aidera à comprendre ce qu'il fait et comment l' utiliser dans votre code.
Qu'est-ce qu'un pool de cordes?
String
est probablement la classe la plus utilisée en Java. Si un nouvel objet était créé dans le tas de mémoire chaque fois que nous utilisions a String
, nous gaspillerions beaucoup de mémoire. Le String
pool résout ce problème en ne stockant qu'un seul objet pour chaque String
valeur, comme indiqué ci-dessous.

Bien que nous ayons créé une String
variable pour les Duke
et Juggy
String
s, seuls deux objets sont créés et stockés dans le tas de mémoire. Pour preuve, regardez l'exemple de code suivant. (Rappelez-vous que l' ==
opérateur « » en Java est utilisé pour comparer deux objets et déterminer s'ils sont identiques.)
String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy);
Ce code sera renvoyé true
car les deux String
pointent vers le même objet dans le String
pool. Leurs valeurs sont les mêmes.
Une exception: l'opérateur 'new'
Maintenant, regardez 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 reviendrait true
, mais c'est en fait false
. L'ajout de l' new
opérateur force la création d'un nouveau String
dans le tas de mémoire. Ainsi, la JVM créera deux objets différents.
Méthodes natives
Une méthode native en Java est une méthode qui sera compilée en utilisant le langage C, généralement dans le but de manipuler la mémoire et d'optimiser les performances.
Pools de chaînes et méthode intern ()
Pour stocker un String
dans la String
piscine, nous utilisons une technique appelée String
internement . Voici ce que Javadoc nous dit de la intern()
méthode:
/** * Returns a canonical representation for the string object. * * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * The Java™ Language Specification. * * @returns a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. * @jls 3.10.5 String Literals */ public native String intern();
La intern()
méthode est utilisée pour stocker les String
s dans un String
pool. Tout d'abord, il vérifie si le que String
vous avez créé existe déjà dans le pool. Sinon, cela crée un nouveau String
dans la piscine. Dans les coulisses, la logique de la String
mise en commun est basée sur le modèle Flyweight.
Maintenant, remarquez ce qui se passe lorsque nous utilisons le new
mot - clé pour forcer la création de deux String
s:
String duke = new String("duke"); String duke2 = new String("duke"); System.out.println(duke == duke2); // The result will be false here System.out.println(duke.intern() == duke2.intern()); // The result will be true here
Contrairement à l'exemple précédent avec le new
mot - clé, dans ce cas, la comparaison s'avère vraie. En effet, l'utilisation de la intern()
méthode garantit que les String
s seront stockés dans le pool.
Méthode Equals avec la classe String
La equals()
méthode est utilisée pour vérifier si l'état de deux classes Java est le même. Parce que equals()
c'est de la Object
classe, chaque classe Java en hérite. Mais la equals()
méthode doit être remplacée pour qu'elle fonctionne correctement. Bien sûr, String
remplace equals()
.
Regarde:
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, l'état de la String
valeur de classe doit être equals()
et non la référence d'objet. Peu importe si la référence d'objet est différente; l'état du String
sera comparé.
Méthodes String les plus courantes
Il y a juste une dernière chose que vous devez savoir avant de String
relever le défi de la comparaison. Considérez ces méthodes courantes de la String
classe:
// Removes spaces from the borders trim() // Gets a substring by indexes substring(int beginIndex, int endIndex) // Returns the characters length of the String length() // Replaces String, regex can be used. replaceAll(String regex, String replacement) // Verifies if there is a specified CharSequence in the String contains(CharSequences)
Relevez le défi de la comparaison de chaînes!
Essayons ce que vous avez appris sur la String
classe dans un défi rapide.
Pour ce défi, vous allez comparer un certain nombre de String
s en utilisant les concepts que nous avons explorés. En regardant le code ci-dessous, pouvez-vous déterminer la valeur finale de chaque variable de résultats ?
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 sortie représente la valeur finale de la variable de résultats?
A : 02468
B : 12469
C : 12579
D : 12568
Vérifiez votre réponse ici.
Qu'est-ce qui vient juste de se passer? Comprendre le comportement des chaînes
Dans la première ligne du code, on voit:
result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1";
Bien que le String
sera le même après l' trim()
appel de la méthode, le String
“ powerfulcode “
était différent au début. Dans ce cas, la comparaison est false
, car lorsque la trim()
méthode supprime les espaces des bordures, elle force la création d'un nouveau String
avec l'opérateur new.
Ensuite, nous voyons:
result += "flexibleCode" == "flexibleCode" ? "2" : "3";
No mystery here, the String
s are the same in the String
pool. This comparison returns true
.
Next, we have:
result += new String("doYourBest") == new String("doYourBest") ? "4" : "5";
Using the new
reserved keyword forces the creation of two new String
s, whether they are equal or not. In this case the comparison will be false
even if the String
values are the same.
Next is:
result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7";
Because we’ve used the equals()
method, the value of the String
will be compared and not the object instance. In that case, it doesn’t matter if the objects are different because the value is being compared. This comparison returns true
.
Finally, we have:
result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9";
As you’ve seen before, the intern()
method puts the String
in the String
pool. Both String
s point to the same object, so in this case the comparison is true
.
Video challenge! Debugging String comparisons
Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video you can follow along while I debug and explain the Java Strings challenge:
Common mistakes with Strings
It can be difficult to know if two String
s are pointing to the same object, especially when the String
s contain the same value. It helps to remember that using the reserved keyword new
always results in a new object being created in memory, even if the values are the same.
Using String
methods to compare Object
references can also be tricky. The key is, if the method changes something in the String
, the object references will be different.
A few examples to help clarify:
System.out.println("duke".trim() == "duke".trim());;
This comparison will be true because the trim()
method does not generate a new String
.
System.out.println(" duke".trim() == "duke".trim());
In this case, the first trim()
method will generate a new String
because the method will execute its action, so the references will be different.
Finally, when trim()
executes its action, it creates a new String
:
// Implementation of the trim method in the String class new String(Arrays.copyOfRange(val, index, index + len), LATIN1);
What to remember about Strings
String
s are immutable, so aString
’s state can’t be changed.- To conserve memory, the JVM keeps
String
s in aString
pool. When a newString
is created, the JVM checks its value and points it to an existing object. If there is noString
with that value in the pool, then the JVM creates a newString
. - L'utilisation de l'
==
opérateur compare la référence de l'objet. L'utilisation de laequals()
méthode compare la valeur deString
. La même règle sera appliquée à tous les objets. - Lors de l'utilisation de l'
new
opérateur, un nouveauString
sera créé dans leString
pool même s'il existe unString
avec la même valeur.
Clé de réponse
La réponse à ce challenger Java est l'option D. La sortie serait 12568
.
Cette histoire, "Comparaisons de chaînes en Java" a été initialement publiée par JavaWorld.