Сравнение строк в Java

В Java Stringкласс инкапсулирует массив файлов char. Проще говоря, Stringэто массив символов, используемый для составления слов, предложений или любых других данных, которые вы хотите.

Инкапсуляция - одна из самых мощных концепций объектно-ориентированного программирования. Из-за инкапсуляции вам не нужно знать, как работает класс String; вам просто нужно знать, какие методы использовать в его интерфейсе.

Когда вы смотрите на Stringкласс в Java, вы можете видеть, как charинкапсулируется массив :

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

Чтобы лучше понять инкапсуляцию, рассмотрим физический объект: автомобиль. Вам нужно знать, как машина работает под капотом, чтобы ездить на ней? Конечно, нет, но вам нужно знать, что делают интерфейсы автомобиля: такие вещи, как акселератор, тормоза и рулевое колесо. Каждый из этих интерфейсов поддерживает определенные действия: ускорение, торможение, поворот налево, поворот направо. То же самое и в объектно-ориентированном программировании.

В моем первом блоге из серии Java Challengers была представлена ​​перегрузка методов, Stringшироко применяемая в классе. Перегрузка может сделать ваши классы действительно гибкими, в том числе 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…... 

Вместо того, чтобы пытаться понять, как Stringработает класс, этот Java Challenger поможет вам понять, что он делает и как использовать его в вашем коде.

Что такое пул строк?

Stringвозможно, наиболее часто используемый класс в Java. Если бы новый объект создавался в куче памяти каждый раз, когда мы использовали a String, мы теряли бы много памяти. StringБассейн решает эту проблему за счет хранения только один объект для каждого Stringзначения, как показано ниже.

Рафаэль Чинелато дель Неро

Хотя мы создали Stringпеременную для Dukeи JuggyString, только два объекта создаются и хранятся в куче памяти. В качестве доказательства посмотрите следующий пример кода. (Напомним, что ==оператор « » в Java используется для сравнения двух объектов и определения, являются ли они одинаковыми.)

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

Этот код вернется, trueпотому что два Strings указывают на один и тот же объект в Stringпуле. Их ценности одинаковы.

Исключение: оператор new.

Теперь взгляните на этот код - он похож на предыдущий пример, но есть разница.

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

Основываясь на предыдущем примере, вы могли подумать, что этот код вернется true, но на самом деле это так false. Добавление newоператора приводит к созданию нового Stringв куче памяти. Таким образом, JVM создаст два разных объекта.

Родные методы

Нативный метод в Java является методом , который будет составлен с использованием языка C, как правило , с целью манипулирования памяти и оптимизацией производительности.

Пулы строк и метод intern ()

Чтобы сохранить Stringв Stringпуле, мы используем метод, называемый Stringинтернированием . Вот что Javadoc сообщает нам о intern()методе:

 /** * 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()Метод используется для хранения Stringы в Stringбассейне. Во-первых, он проверяет, существует ли Stringуже созданный вами объект в пуле. Если нет, он создает новый Stringв пуле. За кулисами логика Stringобъединения основана на паттерне Легковес.

Теперь обратите внимание, что происходит, когда мы используем newключевое слово для принудительного создания двух 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 

В отличие от предыдущего примера с newключевым словом, в этом случае сравнение оказывается верным. Это потому, что использование intern()метода гарантирует, что Strings будет храниться в пуле.

Equals с классом String

equals()Метод используется для проверки , если состояние двух классов Java являются одинаковыми. Поскольку equals()это от Objectкласса, каждый класс Java наследует его. Но equals()метод должен быть переопределен, чтобы он работал правильно. Конечно, Stringотменяет equals().

Взглянуть:

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

Как видите, Stringдолжно быть состояние значения класса, equals()а не ссылка на объект. Не имеет значения, отличается ли ссылка на объект; состояние Stringбудет сравниваться.

Наиболее распространенные методы String

Прежде чем приступить к Stringсравнительному испытанию , вам нужно знать еще кое-что . Рассмотрим эти общие методы Stringкласса:

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

Примите вызов сравнения строк!

Давайте посмотрим, что вы узнали о Stringклассе, в небольшом задании.

Для этого задания вы сравните количество Strings, используя изученные нами концепции. Глядя на приведенный ниже код, можете ли вы определить окончательное значение каждой переменной результатов ?

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

Какой результат представляет собой окончательное значение переменной результатов?

А : 02468

А : 12469

С : 12579

Д : 12568

Проверьте свой ответ здесь.

Что сейчас произошло? Понимание поведения String

В первой строке кода мы видим:

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

Хотя Stringпосле trim()вызова метода он будет таким же, String“ powerfulcode “вначале он был другим. В этом случае сравнение происходит false, потому что, когда trim()метод удаляет пробелы из границ, он принудительно создает новый Stringс оператором new.

Далее мы видим:

 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.
  • Использование ==оператора сравнивает ссылку на объект. С помощью equals()метода сравнивается значение String. То же правило будет применяться ко всем объектам.
  • При использовании newоператора Stringв Stringпуле будет создан новый , даже если есть Stringс таким же значением.

 

Ключ ответа

Ответ на этот Java-претендент - вариант D. Результатом будет 12568.

Этот рассказ «Сравнение строк в Java» был первоначально опубликован JavaWorld.