JavaRush /Java Blog /Random-IT /Uguale in Java e confronto tra stringhe - Confronto tra s...

Uguale in Java e confronto tra stringhe - Confronto tra stringhe

Pubblicato nel gruppo Random-IT
Ciao! Oggi parleremo di un argomento molto importante e interessante, ovvero il confronto tra oggetti tra loro equals() in Java. E infatti, in quali casi in Java l'Oggetto A sarà uguale all'Oggetto B ? Uguali e confronto tra stringhe - 1Proviamo a scrivere un esempio:
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
Uscita console:

false
Ok, fermati. Perché, infatti, queste due auto non sono uguali? Abbiamo dato loro le stesse proprietà, ma il risultato del confronto è falso. La risposta è semplice. L'operatore ==confronta non le proprietà degli oggetti, ma i collegamenti. Anche se due oggetti hanno 500 proprietà identiche, il risultato del confronto sarà comunque falso. Dopotutto, i collegamenti car1puntano car2 a due oggetti diversi , a due indirizzi diversi. Immagina una situazione in cui si confrontano le persone. Probabilmente c'è una persona al mondo che ha il tuo stesso nome, colore degli occhi, età, altezza, colore dei capelli, ecc. Cioè, siete simili in molti modi, ma non siete gemelli, e soprattutto non siete la stessa persona. Uguali e confronto tra stringhe - 2L'operatore applica approssimativamente la stessa logica ==quando lo usiamo per confrontare due oggetti. Ma cosa succede se hai bisogno di una logica diversa nel tuo programma? Ad esempio, se il tuo programma simula l'analisi del DNA. Deve confrontare il codice del DNA di due persone e determinare che sono gemelli.
public class Man {

   int dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1 == man2);
   }
}
Uscita console:

false
È logico che il risultato sia stato lo stesso (dopotutto non abbiamo cambiato nulla), ma ora non ne siamo soddisfatti! In effetti, nella vita reale, l'analisi del DNA è una garanzia al cento per cento che siamo di fronte a gemelli. Ma il nostro programma e il nostro operatore ==ci dicono il contrario. Come possiamo cambiare questo comportamento e assicurarci che, se i test del DNA corrispondono, il programma produrrà il risultato corretto? A questo scopo è stato creato in Java un metodo speciale: equals() .

Metodo Equals() in Java

Come il metodo toString()di cui abbiamo parlato prima, equals() appartiene alla classe, Objectla classe più importante in Java, da cui derivano tutte le altre classi. Tuttavia, equals() di per sé non cambierà in alcun modo il comportamento del nostro programma:
public class Man {

   String dnaCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = "111122223333";

       Man man2 = new Man();
       man2.dnaCode = "111122223333";

       System.out.println(man1.equals(man2));
   }
}
Uscita console:

false
Esattamente lo stesso risultato, quindi perché è necessario questo metodo? :/ È semplice. Il fatto è che ora utilizziamo questo metodo così come è implementato nella classe stessa Object. E se entriamo nel codice della classe Objecte guardiamo come è implementato questo metodo e cosa fa, vedremo:
public boolean equals(Object obj) {
   return (this == obj);
}
Questo è il motivo per cui il comportamento del nostro programma non è cambiato! All'interno del metodo equals() della classe Objectsi trova lo stesso confronto di riferimenti, ==. Ma il trucco di questo metodo è che possiamo ignorarlo. Fare l'override significa scrivere il proprio metodo equals() nella nostra classe Mane farlo comportare nel modo desiderato! Ora non siamo soddisfatti del fatto che check man1.equals(man2)faccia essenzialmente la stessa cosa di man1 == man2. Ecco cosa faremo in questa situazione:
public class Man {

   int dnaCode;

   public boolean equals(Man man) {
       return this.dnaCode ==  man.dnaCode;
   }

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.dnaCode = 1111222233;

       Man man2 = new Man();
       man2.dnaCode = 1111222233;

       System.out.println(man1.equals(man2));

   }
}
Uscita console:

true
Un risultato completamente diverso! Scrivendo il nostro metodo equals() invece di quello standard, abbiamo ottenuto il comportamento corretto: ora se due persone hanno lo stesso codice DNA, il programma ci dice: “L'analisi del DNA ha mostrato che sono gemelli” e restituisce true! Sostituendo il metodo equals() nelle tue classi, puoi facilmente creare la logica di confronto degli oggetti necessaria. Abbiamo toccato il confronto degli oggetti solo in termini generali. Avremo comunque un'ampia conferenza separata su questo argomento più avanti (puoi leggerla velocemente ora, se sei interessato).

Confronto di stringhe in Java - Confronto di stringhe

Perché trattiamo i confronti tra stringhe separatamente da tutto il resto? Ebbene, in effetti, le linee di programmazione sono una storia completamente diversa. In primo luogo, se prendi tutti i programmi Java scritti dall'umanità, circa il 25% degli oggetti in essi contenuti sono costituiti da essi. Pertanto, questo argomento è molto importante. In secondo luogo, il processo di confronto delle stringhe è in realtà molto diverso da quello degli altri oggetti. Diamo un'occhiata a un semplice esempio:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2);
   }
}
Uscita console:

false
Ma perché falso? Le righe sono esattamente le stesse, parola per parola :/ Puoi supporre: questo è perché l'operatore == confronta i riferimenti! Dopotutto, s1hanno s2indirizzi diversi in memoria. Se ti è venuto in mente questo pensiero, allora ripetiamo il nostro esempio:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = "JavaRush is the best site to learn Java!";
       System.out.println(s1 == s2);
   }
}
Ora abbiamo anche due collegamenti, ma il risultato è cambiato nel contrario: Output della console:

true
Completamente confuso? :) Scopriamolo. L'operatore ==confronta effettivamente gli indirizzi in memoria. Questa regola funziona sempre e non c'è bisogno di dubitarne. Ciò significa che se s1 == s2restituisce true, queste due stringhe hanno lo stesso indirizzo in memoria. E infatti lo è! È ora di familiarizzare con un'area di memoria speciale per la memorizzazione delle stringhe: lo string pool ( String pool) Uguali e confronto tra stringhe - 3Lo string pool è un'area per la memorizzazione di tutti i valori di stringa che crei nel tuo programma. Per cosa è stato creato? Come accennato in precedenza, le stringhe occupano gran parte di tutti gli oggetti. In qualsiasi programma di grandi dimensioni vengono create molte righe. Per risparmiare memoria, questo è ciò che serve String Pool: lì viene posizionata una riga con il testo che ti serve e in futuro i collegamenti appena creati si riferiscono alla stessa area di memoria, non è necessario allocare memoria aggiuntiva ogni volta. Ogni volta che si scrive String = “........”, il programma controlla se è presente una riga con tale testo nello string pool. Se esiste, non ne verrà creato uno nuovo. E il nuovo collegamento punterà allo stesso indirizzo nel pool di stringhe in cui è archiviata questa stringa. Pertanto, quando abbiamo scritto nel programma
String s1 = "JavaRush is the best site to learn Java!";
String s2 = "JavaRush is the best site to learn Java!";
il collegamento s2punta esattamente allo stesso posto di s1. Il primo comando creava una nuova riga nello string pool con il testo di cui avevamo bisogno e, quando si arrivava al secondo, si riferiva semplicemente alla stessa area di memoria di s1. Puoi creare almeno altre 500 righe con lo stesso testo, il risultato non cambierà. Fermare. Ma perché questo esempio non ha funzionato per noi prima?
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2);
   }
}
Penso che, intuitivamente, tu abbia già indovinato quale sia il motivo :) Prova a indovinare prima di leggere oltre. Puoi vedere che queste due linee sono state create diversamente. Uno è con l'aiuto dell'operatore newe il secondo senza di esso. Questo è proprio il motivo. L'operatore new, quando crea un oggetto, alloca forzatamente una nuova area di memoria per esso . E la riga creata con new, non finisce in String Pool: diventa un oggetto separato, anche se il suo testo è esattamente uguale alla stessa riga di String Pool'a. Cioè, se scriviamo il seguente codice:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = "JavaRush is the best site to learn Java!";
       String s3 = new String("JavaRush is the best site to learn Java!");
   }
}
In memoria apparirà così: Uguali e confronto tra stringhe - 4E ogni volta che viene creato un nuovo oggetto, newuna nuova area verrà allocata in memoria, anche se il testo all'interno delle nuove righe è lo stesso! Sembra che abbiamo risolto l'operatore ==, ma per quanto riguarda il nostro nuovo amico: il metodo equals()?
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1.equals(s2));
   }
}
Uscita console:

true
Interessante. Sappiamo esattamente cosa s1e s2indichiamo diverse aree della memoria. Tuttavia, il metodo equals() dice che sono uguali. Perché? Ricorda, sopra abbiamo detto che il metodo equals() può essere sovrascritto nella tua classe in modo che confronti gli oggetti nel modo desiderato? Questo è quello che hanno fatto con la classe String. Ha un metodo equals() sovrascritto. E non confronta i collegamenti, ma piuttosto la sequenza di caratteri nelle stringhe. E se il testo nelle stringhe è lo stesso, non importa come sono state create e dove sono archiviate: nello string pool o in un'area di memoria separata. Il risultato del confronto sarà vero. A proposito, Java ti consente di confrontare correttamente le stringhe senza distinzione tra maiuscole e minuscole. In una situazione normale, se scrivi una delle righe, ad esempio, in maiuscolo, il risultato del confronto sarà falso:
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JAVARUSH - ЛУЧШИЙ САЙТ ДЛЯ ИЗУЧЕНИЯ JAVA!");
       System.out.println(s1.equals(s2));
   }
}
Uscita console:

false
In questo caso, la classe Stringha un metodo equalsIgnoreCase(). Se la cosa principale nel tuo confronto è la sequenza di caratteri specifici e non il loro caso, puoi usarla. Ad esempio, questo sarà utile quando si confrontano due indirizzi email:
public class Main {

   public static void main(String[] args) {

       String address1 = "Moscow, Academician Korolev street, 12";
       String address2 = new String("Г. МОСКВА, УЛ. АКАДЕМИКА КОРОЛЕВА, ДОМ 12");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
In questo caso è ovvio che stiamo parlando dello stesso indirizzo, quindi utilizzare questo metodo equalsIgnoreCase()sarà la decisione giusta.

Metodo String.intern()

La classe Stringha un altro metodo complicato: intern(); Il metodo intern()funziona direttamente con String Pool'om. Se chiami un metodo intern()su una stringa, esso:
  • Cerca se c'è una stringa con questo testo nel pool di stringhe
  • Se c'è, restituisce un collegamento al pool
  • In caso contrario, inserisce una riga con questo testo nello string pool e restituisce un collegamento ad esso.
Applicando il metodo intern()al riferimento alla stringa creato tramite new, possiamo confrontarlo con il riferimento alla stringa da String Pool'a tramite ==.
public class Main {

   public static void main(String[] args) {

       String s1 = "JavaRush is the best site to learn Java!";
       String s2 = new String("JavaRush is the best site to learn Java!");
       System.out.println(s1 == s2.intern());
   }
}
Uscita console:

true
In precedenza, quando li confrontavamo senza intern(), il risultato era falso. Ora il metodo intern()controlla se c'è una riga con il testo "JavaRush - il miglior sito per imparare Java!" nel pool di stringhe. Certo che è lì: l'abbiamo creato noi mentre lo scrivevamo
String s1 = "JavaRush is the best site to learn Java!";
È stato verificato che il riferimento s1e il riferimento restituito dal metodo s2.intern()puntino alla stessa area di memoria e, ovviamente, lo fanno :) Per riassumere, ricordare e utilizzare la regola principale: per confrontare stringhe, utilizzare SEMPRE equals() metodo! Quando si confrontano le stringhe, si intende quasi sempre confrontare il loro testo, non i collegamenti, le aree di memoria e così via. Il metodo equals() fa esattamente ciò di cui hai bisogno. Ecco alcuni link per studiare da solo:
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION