Zeichenfolgenvergleiche in Java

In Java Stringkapselt die Klasse ein Array von char. Einfach Stringausgedrückt ist eine Reihe von Zeichen, die zum Zusammenstellen von Wörtern, Sätzen oder anderen gewünschten Daten verwendet werden.

Die Kapselung ist eines der mächtigsten Konzepte in der objektorientierten Programmierung. Aufgrund der Kapselung müssen Sie nicht wissen, wie die String-Klasse funktioniert. Sie müssen nur wissen, welche Methoden auf der Benutzeroberfläche verwendet werden sollen.

Wenn Sie sich die StringKlasse in Java ansehen , können Sie sehen, wie das Array von chargekapselt ist:

 public String(char value[]) { this(value, 0, value.length, null); } 

Um die Kapselung besser zu verstehen, betrachten Sie ein physisches Objekt: ein Auto. Müssen Sie wissen, wie das Auto unter der Motorhaube funktioniert, um es zu fahren? Natürlich nicht, aber Sie müssen wissen, was die Schnittstellen des Autos bewirken: Dinge wie Gaspedal, Bremsen und Lenkrad. Jede dieser Schnittstellen unterstützt bestimmte Aktionen: Beschleunigen, Bremsen, links abbiegen, rechts abbiegen. Dies gilt auch für die objektorientierte Programmierung.

In meinem ersten Blog in der Java Challengers- Reihe wurde das Überladen von Methoden vorgestellt, eine Technik, die die StringKlasse ausgiebig verwendet. Überladen kann Ihre Klassen wirklich flexibel machen, einschließlich 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…... 

Anstatt zu versuchen zu verstehen, wie die StringKlasse funktioniert, hilft Ihnen dieser Java Challenger zu verstehen, was er tut und wie er in Ihrem Code verwendet wird.

Was ist ein String-Pool?

Stringist möglicherweise die am häufigsten verwendete Klasse in Java. Wenn jedes Mal String, wenn wir ein neues Objekt verwenden, ein neues Objekt im Speicherhaufen erstellt wird , verschwenden wir viel Speicher. Der StringPool löst dieses Problem, indem nur ein Objekt für jeden StringWert gespeichert wird, wie unten gezeigt.

Rafael Chinelato Del Nero

Obwohl wir eine StringVariable für Dukeund erstellt haben JuggyString, werden nur zwei Objekte erstellt und im Speicherheap gespeichert. Schauen Sie sich zum Beweis das folgende Codebeispiel an. (Denken Sie daran, dass der ==Operator " " in Java verwendet wird, um zwei Objekte zu vergleichen und festzustellen, ob sie gleich sind.)

 String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy); 

Dieser Code wird zurückgegeben, trueda die beiden Strings auf dasselbe Objekt im StringPool verweisen . Ihre Werte sind die gleichen.

Eine Ausnahme: Der 'neue' Operator

Schauen Sie sich jetzt diesen Code an - er sieht ähnlich aus wie das vorherige Beispiel, aber es gibt einen Unterschied.

 String duke = new String("duke"); String anotherDuke = new String("duke"); System.out.println(duke == anotherDuke); 

Basierend auf dem vorherigen Beispiel könnten Sie denken, dass dieser Code zurückkehren würde true, aber es ist tatsächlich so false. Durch Hinzufügen des newOperators wird die Erstellung eines neuen Stringim Speicherheap erzwungen. Somit erstellt die JVM zwei verschiedene Objekte.

Native Methoden

Eine native Methode in Java ist eine Methode, die in der Sprache C kompiliert wird, normalerweise um den Speicher zu manipulieren und die Leistung zu optimieren.

String-Pools und die intern () -Methode

Um ein Stringim StringPool zu speichern , verwenden wir eine Technik namens StringInterning . Folgendes sagt uns Javadoc über die intern()Methode:

 /** * 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(); 

Die intern()Methode wird verwendet, um Strings in einem StringPool zu speichern . Zunächst wird überprüft, ob das von StringIhnen erstellte bereits im Pool vorhanden ist. Wenn nicht, wird ein neuer Stringim Pool erstellt. Hinter den Kulissen Stringbasiert die Logik des Pooling auf dem Flyweight-Muster.

Beachten Sie nun, was passiert, wenn wir das newSchlüsselwort verwenden, um die Erstellung von zwei Strings zu erzwingen :

 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 

Im Gegensatz zum vorherigen Beispiel mit dem newSchlüsselwort stellt sich in diesem Fall der Vergleich als wahr heraus. Dies liegt daran, dass durch die Verwendung der intern()Methode sichergestellt Stringwird, dass das s im Pool gespeichert wird.

Entspricht der Methode der String-Klasse

Die equals()Methode wird verwendet, um zu überprüfen, ob der Status von zwei Java-Klassen identisch ist. Da equals()es von der ObjectKlasse stammt, erbt jede Java-Klasse es. Die equals()Methode muss jedoch überschrieben werden, damit sie ordnungsgemäß funktioniert. Natürlich Stringüberschreibt equals().

Schau mal:

 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; } 

Wie Sie sehen können, muss der Status des StringKlassenwerts equals()und nicht die Objektreferenz sein. Es spielt keine Rolle, ob die Objektreferenz unterschiedlich ist. Der Zustand des Stringwird verglichen.

Die gebräuchlichsten String-Methoden

Es gibt nur eine letzte Sache, die Sie wissen müssen, bevor Sie die StringVergleichsherausforderung annehmen. Betrachten Sie diese allgemeinen Methoden der StringKlasse:

 // 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) 

Nehmen Sie die String-Vergleichs-Herausforderung an!

Lassen Sie uns Stringin einer kurzen Herausforderung ausprobieren, was Sie über die Klasse gelernt haben .

Für diese Herausforderung vergleichen Sie eine Reihe von Strings mit den von uns untersuchten Konzepten. Können Sie anhand des folgenden Codes den Endwert jeder Ergebnisvariablen bestimmen ?

 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); } } 

Welche Ausgabe repräsentiert den Endwert der Ergebnisvariablen?

A : 02468

B : 12469

C : 12579

D : 12568

Überprüfen Sie hier Ihre Antwort.

Was ist gerade passiert? Grundlegendes zum Verhalten von Zeichenfolgen

In der ersten Zeile des Codes sehen wir:

 result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; 

Obwohl das Stringnach dem trim()Aufrufen der Methode gleich ist, String“ powerfulcode “war das am Anfang anders. In diesem Fall ist der Vergleich false, denn wenn die trim()Methode Leerzeichen von den Rändern entfernt, erzwingt sie die Erstellung eines neuen Stringmit dem neuen Operator.

Als nächstes sehen wir:

 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.
  • Mit dem ==Operator wird die Objektreferenz verglichen. Mit der equals()Methode wird der Wert von verglichen String. Die gleiche Regel wird auf alle Objekte angewendet.
  • Bei Verwendung des newOperators Stringwird im StringPool ein neuer Operator erstellt, auch wenn es einen Stringmit demselben Wert gibt.

 

Lösungsschlüssel

Die Antwort auf diesen Java-Herausforderer lautet Option D. Die Ausgabe wäre 12568.

Diese Geschichte "String-Vergleiche in Java" wurde ursprünglich von JavaWorld veröffentlicht.