Сравнение на низове в 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 pool?

Stringе може би най-използваният клас в Java. Ако в купчината памет се създава нов обект всеки път, когато използваме a String, бихме загубили много памет. В Stringбасейна решава този проблем, като съхранява само един обект за всяка Stringстойност, както е показано по-долу.

Рафаел Чинелато Дел Неро

Въпреки че създадохме Stringпроменлива за Dukeи JuggyString, само два обекта се създават и съхраняват в купчината памет. За доказателство погледнете следния пример за код. (Спомнете си, че ==операторът “ ” в Java се използва за сравняване на два обекта и определяне дали те са еднакви.)

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

Този код ще се върне, trueзащото двете Strings сочат към един и същ обект в Stringпула. Стойностите им са еднакви.

Изключение: „Новият“ оператор

Сега погледнете този код - той изглежда подобен на предишния пример, но има разлика.

 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обединяването се основава на модела Flyweight.

Сега забележете какво се случва, когато използваме 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 ще се съхраняват в пула.

Методът е равен на класа 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класа:

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

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

A : 02468

B : 12469

C : 12579

D : 12568

Проверете отговора си тук.

Какво се случи току що? Разбиране на поведението на низ

В първия ред на кода виждаме:

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

Въпреки че Stringслед trim()извикването на метода ще бъде същото , то String“ powerfulcode “в началото беше различно. В този случай сравнението е false, защото когато trim()методът премахва интервали от границите, той налага създаването на нов Stringс новия оператор.

След това виждаме:

 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пула ще се създаде нов, дори ако има a Stringсъс същата стойност.

 

Клавиш за отговор

Отговорът на този Java претендент е вариант D. Резултатът ще бъде 12568.

Тази история „Сравнения на низове в Java“ първоначално е публикувана от JavaWorld.