Strängjämförelser i Java

I Java Stringinkapslar klassen en matris av char. Enkelt uttryckt Stringär en rad tecken som används för att komponera ord, meningar eller annan information du vill ha.

Inkapsling är ett av de mest kraftfulla begreppen inom objektorienterad programmering. På grund av inkapsling behöver du inte veta hur strängklassen fungerar; du behöver bara veta vilka metoder som ska användas i dess gränssnitt.

När du tittar på Stringklassen i Java kan du se hur matrisen charär inkapslad:

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

För att bättre förstå inkapsling, överväg ett fysiskt objekt: en bil. Behöver du veta hur bilen fungerar under huven för att kunna köra den? Naturligtvis inte, men du behöver veta vad gränssnitten på bilen gör: saker som gaspedalen, bromsarna och ratten. Var och en av dessa gränssnitt stöder vissa åtgärder: accelerera, bromsa, sväng vänster, sväng höger. Det är samma sak i objektorienterad programmering.

Min första blogg i Java Challengers- serien introducerade metodöverbelastning, vilket är en teknik som Stringklassen använder i stor utsträckning. Överbelastning kan göra dina lektioner riktigt flexibla, inklusive 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…... 

I stället för att försöka förstå hur Stringklassen fungerar, hjälper den här Java Challenger dig att förstå vad den gör och hur du använder den i din kod.

Vad är en strängpool?

Stringär möjligen den mest använda klassen i Java. Om ett nytt objekt skapades i minneshögen varje gång vi använde a String, skulle vi slösa mycket minne. Den Stringpool löser detta problem genom att lagra bara ett objekt för varje Stringvärde, som visas nedan.

Rafael Chinelato Del Nero

Även om vi skapade en Stringvariabel för Dukeoch JuggyStrings skapas och lagras bara två objekt i minneshög. För bevis, titta på följande kodprov. (Kom ihåg att ==operatören " " i Java används för att jämföra två objekt och avgöra om de är desamma.)

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

Den här koden kommer tillbaka trueeftersom de två Stringpekar på samma objekt i Stringpoolen. Deras värderingar är desamma.

Ett undantag: Den "nya" operatören

Titta nu på den här koden - den liknar det tidigare exemplet, men det finns en skillnad.

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

Baserat på föregående exempel kanske du tror att den här koden skulle återvända true, men den är faktiskt false. Genom att lägga till newoperatören tvingas skapandet av ett nytt Stringi minneshög. Således kommer JVM att skapa två olika objekt.

Native metoder

En inbyggd metod i Java är en metod som kommer att sammanställas med C-språket, vanligtvis för att manipulera minne och optimera prestanda.

Strängpooler och intern () -metoden

För att lagra en Stringi Stringpoolen använder vi en teknik som kallas Stringinterning . Här är vad Javadoc berättar om intern()metoden:

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

Den intern()metod som används för att lagra Stringsi en Stringpool. Först verifierar det om det Stringdu har skapat redan finns i poolen. Om inte skapar det ett nytt Stringi poolen. Bakom kulisserna är logiken med Stringpoolning baserad på flygviktsmönstret.

Lägg märke till vad som händer när vi använder newnyckelordet för att tvinga skapandet av två 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 

Till skillnad från föregående exempel med newnyckelordet visar sig jämförelsen i det här fallet vara sant. Det beror på att användning av intern()metoden säkerställer att Strings kommer att lagras i poolen.

Lika med metoden String-klassen

Den equals()metod som används för att kontrollera om tillståndet hos två Java-klasser är desamma. Eftersom det equals()är från Objectklassen ärver varje Java-klass det. Men equals()metoden måste åsidosättas för att få den att fungera ordentligt. Naturligtvis Stringåsidosätter equals().

Ta en titt:

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

Som du kan se Stringmåste klassvärdets tillstånd vara equals()och inte objektreferensen. Det spelar ingen roll om objektreferensen är annorlunda; Stringviljans tillstånd jämförs.

De vanligaste strängmetoderna

Det finns bara en sista sak du behöver veta innan du tar Stringjämförelseutmaningen. Tänk på dessa vanliga metoder i Stringklassen:

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

Ta strängjämförelsesutmaningen!

Låt oss prova vad du har lärt dig om Stringklassen i en snabb utmaning.

För den här utmaningen jämför du ett antal Strings med de begrepp vi har utforskat. Om du tittar på koden nedan kan du bestämma det slutliga värdet för varje resultatvariabel ?

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

Vilken utgång representerar slutvärdet för resultatvariabeln?

A : 02468

B : 12469

C : 12579

D : 12568

Kontrollera ditt svar här.

Vad hände nyss? Förstå strängbeteende

I den första raden i koden ser vi:

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

Även om det Stringkommer att vara detsamma efter att trim()metoden har åberopats String“ powerfulcode “var det annorlunda i början. I det här fallet är jämförelsen false, för när trim()metoden tar bort mellanslag från gränserna tvingar den skapandet av ett nytt Stringmed den nya operatören.

Därefter ser vi:

 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.
  • Användning av ==operatören jämför objektreferensen. Med equals()metoden jämförs värdet på String. Samma regel kommer att tillämpas på alla objekt.
  • När du använder newoperatören Stringskapas en ny i Stringpoolen även om det finns en Stringmed samma värde.

 

Svarsknapp

Svaret på denna Java-utmanare är alternativ D. Utdata skulle vara 12568.

Denna berättelse, "Strängjämförelser i Java" publicerades ursprungligen av JavaWorld.