Confronti di stringhe in Java

In Java, la Stringclasse incapsula un array di char. In Stringparole povere, è una matrice di caratteri utilizzata per comporre parole, frasi o qualsiasi altro dato che desideri.

L'incapsulamento è uno dei concetti più potenti nella programmazione orientata agli oggetti. A causa dell'incapsulamento, non è necessario sapere come funziona la classe String; hai solo bisogno di sapere quali metodi usare sulla sua interfaccia.

Quando guardi la Stringclasse in Java, puoi vedere come l'array di charè incapsulato:

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

Per comprendere meglio l'incapsulamento, considera un oggetto fisico: un'auto. Hai bisogno di sapere come funziona l'auto sotto il cofano per guidarla? Certo che no, ma devi sapere cosa fanno le interfacce dell'auto: cose come l'acceleratore, i freni e il volante. Ciascuna di queste interfacce supporta determinate azioni: accelera, frena, gira a sinistra, gira a destra. È lo stesso nella programmazione orientata agli oggetti.

Il mio primo blog nella serie Java Challengers ha introdotto il sovraccarico del metodo, che è una tecnica che la Stringclasse utilizza ampiamente. Il sovraccarico può rendere le tue classi davvero flessibili, tra cui 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…... 

Piuttosto che cercare di capire come funziona la Stringclasse, questo Java Challenger ti aiuterà a capire cosa fa e come usarlo nel tuo codice.

Cos'è un pool di stringhe?

Stringè forse la classe più utilizzata in Java. Se un nuovo oggetto fosse creato nell'heap di memoria ogni volta che usassimo a String, sprecheremmo molta memoria. Il Stringpool risolve questo problema memorizzando un solo oggetto per ogni Stringvalore, come mostrato di seguito.

Rafael Chinelato Del Nero

Sebbene abbiamo creato una Stringvariabile per Dukee JuggyStrings, solo due oggetti vengono creati e archiviati nell'heap di memoria. Per prova, guarda il seguente codice di esempio. (Ricorda che l' ==operatore " " in Java viene utilizzato per confrontare due oggetti e determinare se sono uguali.)

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

Questo codice verrà restituito trueperché i due Stringpuntano allo stesso oggetto nel Stringpool. I loro valori sono gli stessi.

Un'eccezione: l'operatore "nuovo"

Ora guarda questo codice: sembra simile all'esempio precedente, ma c'è una differenza.

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

Sulla base dell'esempio precedente, potresti pensare che questo codice tornerà true, ma in realtà è false. L'aggiunta newdell'operatore forza la creazione di un nuovo Stringnell'heap di memoria. Pertanto, la JVM creerà due oggetti diversi.

Metodi nativi

Un metodo nativo in Java è un metodo che verrà compilato utilizzando il linguaggio C, solitamente allo scopo di manipolare la memoria e ottimizzare le prestazioni.

Pool di stringhe e metodo intern ()

Per conservare un Stringin Stringpiscina, usiamo una tecnica chiamata Stringinterning . Ecco cosa ci dice Javadoc sul intern()metodo:

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

Il intern()metodo viene utilizzato per memorizzare Stringi messaggi di posta elettronica in un Stringpool. Innanzitutto, verifica se l'elemento Stringche hai creato esiste già nel pool. In caso contrario, ne crea una nuova Stringnella piscina. Dietro le quinte, la logica del Stringpooling si basa sul modello Flyweight.

Ora, nota cosa succede quando usiamo la newparola chiave per forzare la creazione di due 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 

A differenza dell'esempio precedente con la newparola chiave, in questo caso il confronto risulta essere vero. Questo perché l'utilizzo del intern()metodo garantisce che i messaggi di posta Stringelettronica vengano archiviati nel pool.

Metodo Equals con la classe String

Il equals()metodo viene utilizzato per verificare se lo stato di due classi Java è lo stesso. Poiché equals()proviene dalla Objectclasse, ogni classe Java lo eredita. Ma il equals()metodo deve essere sovrascritto per farlo funzionare correttamente. Ovviamente, Stringsostituisce equals().

Guarda:

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

Come puoi vedere, lo stato del Stringvalore della classe deve essere equals()e non il riferimento all'oggetto. Non importa se il riferimento all'oggetto è diverso; lo stato della Stringverrà confrontato.

Metodi String più comuni

C'è solo un'ultima cosa che devi sapere prima di affrontare la Stringsfida del confronto. Considera questi metodi comuni della Stringclasse:

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

Accetta la sfida del confronto delle stringhe!

Proviamo ciò che hai imparato sulla Stringclasse in una rapida sfida.

Per questa sfida, confronterai un numero di messaggi di posta Stringelettronica utilizzando i concetti che abbiamo esplorato. Guardando il codice seguente, puoi determinare il valore finale di ciascuna variabile dei risultati ?

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

Quale output rappresenta il valore finale della variabile dei risultati?

A : 02468

B : 12469

C : 12579

D : 12568

Controlla la tua risposta qui.

Cosa è appena successo? Comprensione del comportamento delle stringhe

Nella prima riga del codice, vediamo:

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

Sebbene Stringsarà lo stesso dopo che il trim()metodo è stato invocato, all'inizio String“ powerfulcode “era diverso. In questo caso il confronto è false, perché quando il trim()metodo rimuove gli spazi dai bordi forza la creazione di un nuovo Stringcon il nuovo operatore.

Successivamente, vediamo:

 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.
  • L'utilizzo ==dell'operatore confronta il riferimento all'oggetto. Utilizzando il equals()metodo si confronta il valore di String. La stessa regola verrà applicata a tutti gli oggetti.
  • Quando si utilizza l' newoperatore, Stringverrà creato un nuovo nel Stringpool anche se è presente un Stringcon lo stesso valore.

 

Tasto di risposta

La risposta a questo sfidante Java è l'opzione D. L'output sarebbe 12568.

Questa storia, "Confronti di stringhe in Java" è stata originariamente pubblicata da JavaWorld.