Comparaisons de chaînes en Java

En Java, la Stringclasse encapsule un tableau de char. En termes simples, Stringun 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 Stringclasse en Java, vous pouvez voir comment le tableau de charest 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 Stringclasse 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 Stringclasse, 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?

Stringest 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 Stringpool résout ce problème en ne stockant qu'un seul objet pour chaque Stringvaleur, comme indiqué ci-dessous.

Rafael Chinelato Del Nero

Bien que nous ayons créé une Stringvariable pour les Dukeet JuggyStrings, 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é truecar les deux Stringpointent vers le même objet dans le Stringpool. 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' newopérateur force la création d'un nouveau Stringdans 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 Stringdans la Stringpiscine, nous utilisons une technique appelée Stringinternement . 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 Strings dans un Stringpool. Tout d'abord, il vérifie si le que Stringvous avez créé existe déjà dans le pool. Sinon, cela crée un nouveau Stringdans la piscine. Dans les coulisses, la logique de la Stringmise en commun est basée sur le modèle Flyweight.

Maintenant, remarquez ce qui se passe lorsque nous utilisons le newmot - clé pour forcer la création de deux Strings:

 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 newmot - clé, dans ce cas, la comparaison s'avère vraie. En effet, l'utilisation de la intern()méthode garantit que les Strings 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 Objectclasse, chaque classe Java en hérite. Mais la equals()méthode doit être remplacée pour qu'elle fonctionne correctement. Bien sûr, Stringremplace 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 Stringvaleur 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 Stringsera comparé.

Méthodes String les plus courantes

Il y a juste une dernière chose que vous devez savoir avant de Stringrelever le défi de la comparaison. Considérez ces méthodes courantes de la Stringclasse:

 // 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 Stringclasse dans un défi rapide.

Pour ce défi, vous allez comparer un certain nombre de Strings 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 Stringsera 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 Stringavec l'opérateur new.

Ensuite, nous voyons:

 result += "flexibleCode" == "flexibleCode" ? "2" : "3"; 

No mystery here, the Strings 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 Strings, 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 Strings 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 Strings are pointing to the same object, especially when the Strings 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

  • Strings are immutable, so a String’s state can’t be changed.
  • To conserve memory, the JVM keeps Strings in a String pool. When a new String is created, the JVM checks its value and points it to an existing object. If there is no String with that value in the pool, then the JVM creates a new String.
  • L'utilisation de l' ==opérateur compare la référence de l'objet. L'utilisation de la equals()méthode compare la valeur de String. La même règle sera appliquée à tous les objets.
  • Lors de l'utilisation de l' newopérateur, un nouveau Stringsera créé dans le Stringpool même s'il existe un Stringavec 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.