Porównania ciągów w Javie

W Javie Stringklasa hermetyzuje tablicę char. Mówiąc prościej, Stringjest to tablica znaków używanych do tworzenia słów, zdań lub innych potrzebnych danych.

Hermetyzacja to jedna z najpotężniejszych koncepcji programowania zorientowanego obiektowo. Ze względu na hermetyzację nie musisz wiedzieć, jak działa klasa String; musisz tylko wiedzieć, jakich metod użyć w jego interfejsie.

Kiedy spojrzysz na Stringklasę w Javie, możesz zobaczyć, jak tablica charjest hermetyzowana:

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

Aby lepiej zrozumieć hermetyzację, rozważ obiekt fizyczny: samochód. Czy musisz wiedzieć, jak samochód pracuje pod maską, żeby nim jeździć? Oczywiście, że nie, ale musisz wiedzieć, co robią interfejsy samochodu: takie rzeczy, jak pedał przyspieszenia, hamulce i kierownica. Każdy z tych interfejsów obsługuje określone czynności: przyspieszanie, hamowanie, skręcanie w lewo, skręcanie w prawo. Tak samo jest w programowaniu obiektowym.

Mój pierwszy blog z serii Java Challengers przedstawił przeciążanie metod, czyli technikę, z której Stringklasa korzysta bardzo często. Przeciążenie może uczynić Twoje zajęcia naprawdę elastycznymi, w tym 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…... 

Zamiast próbować zrozumieć, jak Stringdziała klasa, ten program Java Challenger pomoże ci zrozumieć, co robi i jak go używać w kodzie.

Co to jest pula String?

Stringjest prawdopodobnie najczęściej używaną klasą w Javie. Gdyby nowy obiekt był tworzony w stercie pamięci za każdym razem, gdy użyliśmy a String, marnowalibyśmy dużo pamięci. StringBasen rozwiązuje ten problem poprzez przechowywanie tylko jeden obiekt dla każdej Stringwartości, jak pokazano poniżej.

Rafael Chinelato Del Nero

Chociaż utworzyliśmy Stringzmienną dla Dukei JuggyStrings, tylko dwa obiekty są tworzone i przechowywane w stercie pamięci. Aby uzyskać dowód, spójrz na następujący przykład kodu. (Przypomnij sobie, że ==operator „ ” w Javie służy do porównywania dwóch obiektów i określania, czy są takie same).

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

Ten kod zwróci, trueponieważ dwa Strings wskazują ten sam obiekt w Stringpuli. Ich wartości są takie same.

Wyjątek: operator „nowy”

Teraz spójrz na ten kod - wygląda podobnie do poprzedniego przykładu, ale jest różnica.

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

Opierając się na poprzednim przykładzie, możesz pomyśleć, że ten kod zwróci true, ale w rzeczywistości tak jest false. Dodanie newoperatora wymusza utworzenie nowego Stringw stercie pamięci. W ten sposób JVM utworzy dwa różne obiekty.

Metody natywne

Natywny sposób w Javie jest metodą, która zostanie skompilowany przy użyciu języka C, zwykle w celu manipulowania pamięci i optymalizację wydajności.

Pule ciągów i metoda intern ()

Aby przechowywać Stringw Stringpuli, używamy techniki zwanej Stringinterning . Oto, co Javadoc mówi nam o tej intern()metodzie:

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

intern()Metoda jest używana do przechowywania Strings w Stringbasenie. Najpierw sprawdza, czy Stringutworzony plik już istnieje w puli. Jeśli nie, tworzy nowy Stringw puli. Za kulisami logika Stringpoolingu opiera się na wzorcu Flyweight.

Teraz zwróć uwagę, co się stanie, gdy użyjemy newsłowa kluczowego, aby wymusić utworzenie dwóch 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 

W przeciwieństwie do poprzedniego przykładu ze newsłowem kluczowym, w tym przypadku porównanie okazuje się prawdziwe. Dzieje się tak, ponieważ użycie tej intern()metody zapewnia, że Strings będą przechowywane w puli.

Equals z klasą String

equals()Metoda służy do sprawdzenia, czy stan dwóch klas Javy są takie same. Ponieważ equals()pochodzi z Objectklasy, każda klasa Java ją dziedziczy. Ale equals()metoda musi zostać zastąpiona, aby działała poprawnie. Oczywiście Stringnadpisuje equals().

Spójrz:

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

Jak widać, stan Stringwartości klasy musi być, equals()a nie odniesieniem do obiektu. Nie ma znaczenia, czy odniesienie do obiektu jest inne; stan Stringwoli zostanie porównany.

Najpopularniejsze metody String

Jest jeszcze jedna rzecz, którą musisz wiedzieć przed podjęciem Stringwyzwania porównawczego. Rozważ te typowe metody Stringklasy:

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

Podejmij wyzwanie porównania ciągów!

Wypróbujmy, czego nauczyłeś się o Stringklasie w szybkim wyzwaniu.

W tym wyzwaniu porównasz kilka z nich, Stringkorzystając z pojęć, które zbadaliśmy. Patrząc na kod poniżej, można określić ostatecznej wartości poszczególnych wyników zmiennej?

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

Który wynik reprezentuje końcową wartość zmiennej wyników?

O : 02468

B : 12469

C : 12579

D : 12568

Sprawdź swoją odpowiedź tutaj.

Co się stało? Zrozumienie zachowania String

W pierwszym wierszu kodu widzimy:

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

Chociaż Stringbędzie to samo po trim()wywołaniu metody, na początku String“ powerfulcode “było inaczej. W tym przypadku porównanie jest takie false, ponieważ gdy trim()metoda usuwa spacje z granic, wymusza utworzenie nowego Stringz operatorem new.

Następnie widzimy:

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

Żadnej tajemnicy, Stringw Stringbasenie są takie same . To porównanie powraca true.

Następnie mamy:

 result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; 

Użycie newzastrzeżonego słowa kluczowego wymusza utworzenie dwóch nowych Strings, niezależnie od tego, czy są one równe, czy nie. W takim przypadku porównanie będzie miało miejsce falsenawet wtedy, gdy Stringwartości będą takie same.

Następne jest:

 result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; 

Ponieważ użyliśmy tej equals()metody, Stringzostanie porównana wartość elementu, a nie instancja obiektu. W takim przypadku nie ma znaczenia, czy obiekty są różne, ponieważ porównywana jest wartość. To porównanie powraca true.

Wreszcie mamy:

 result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; 

Jak widzieliście wcześniej, intern()metoda umieszcza Stringw Stringpuli. Oba Stringwskazują na ten sam obiekt, więc w tym przypadku jest porównanie 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.
  • Użycie ==operatora porównuje odniesienie do obiektu. Za pomocą tej equals()metody porównuje się wartość String. Ta sama zasada zostanie zastosowana do wszystkich obiektów.
  • Podczas korzystania z newoperatora Stringw Stringpuli zostanie utworzony nowy, nawet jeśli istnieje element Stringo tej samej wartości.

 

Klucz odpowiedzi

Odpowiedzią na to wyzwanie w Javie jest opcja D. Wynik byłby taki 12568.

Ta historia „Porównania ciągów w Javie” została pierwotnie opublikowana przez JavaWorld.