CodeGym /Java-blogg /Tilfeldig /Sammenlign String og Equals sammenligninger i Java
John Squirrels
Nivå
San Francisco

Sammenlign String og Equals sammenligninger i Java

Publisert i gruppen
Hei! I dag skal vi snakke om et veldig viktig og interessant emne, nemlig å sammenligne objekter med objekter (Sammenlign strenger og like). Så i Java, når vil objekt A være lik objekt B ? La oss prøve å skrive et eksempel:

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);
   }
}
Konsollutgang: usant Vent, stopp. Hvorfor er det slik at disse to bilene ikke er like? Vi tildelte dem de samme egenskapene, men resultatet av sammenligningen er usant. Svaret er enkelt. Operatoren == sammenligner objektreferanser, ikke objektegenskaper. To objekter kan til og med ha 500 felt med identiske verdier, men å sammenligne dem vil fortsatt gi falsk. Refererer tross alt til bil1 og bil2peke på to forskjellige objekter, dvs. på to forskjellige adresser. Se for deg en situasjon der du sammenligner mennesker. Visst, et sted i verden er det en person som deler ditt samme navn, øyenfarge, alder, høyde, hårfarge osv. Det gjør deg lik på mange måter, men du er fortsatt ikke tvillinger - og du er åpenbart ikke samme person.
Lik og strengsammenligninger - 2
Operatoren == bruker omtrent den samme logikken når vi bruker den til å sammenligne to objekter. Men hva om du trenger at programmet ditt bruker annen logikk? Anta for eksempel at programmet ditt utfører DNA-analyse. Den sammenligner den genetiske koden til to personer, og avgjør om de er tvillinger.

public class Man {

   int geneticCode;

   public static void main(String[] args) {

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

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

       System.out.println(man1 == man2);
   }
}
Konsollutgang: usann Vi får det samme logiske resultatet (fordi vi ikke endret mye), men nå er ikke den logikken bra! Tross alt, i det virkelige liv, bør DNA-analyse gi oss en 100 % garanti for at vi har tvillinger stående foran oss. Men programmet vårt og ==- operatøren forteller oss det motsatte. Hvordan endrer vi denne oppførselen og sørger for at programmet gir riktig resultat når DNA-en samsvarer? Java har en spesiell metode for dette: equals() . I likhet med toString()- metoden, som vi diskuterte tidligere, tilhører equals() klassen Object — den viktigste klassen i Java, klassen som alle andre klasser stammer fra. Men lik()endrer ikke programmets oppførsel av seg selv:

public class Man {

   String geneticCode;

   public static void main(String[] args) {

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

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

       System.out.println(man1.equals(man2));
   }
}
Konsollutgang: usann Nøyaktig samme resultat, så hva trenger vi denne metoden til? :/ Det hele er enkelt. Problemet her er at vi for øyeblikket bruker denne metoden slik den er implementert i Object- klassen. Og hvis vi går inn i koden til Object- klassen og ser på metodens implementering, er dette hva vi får se:

public boolean equals(Object obj) {
   return (this == obj);
}
Det er grunnen til at programmets oppførsel ikke har endret seg! Den samme ==- operatoren (som sammenligner referanser) brukes i equals()- metoden til Object- klassen. Men trikset med denne metoden er at vi kan overstyre den. Å overstyre betyr å skrive din egen equals()- metode i vår Man- klasse, og gi den oppførselen vi trenger! For øyeblikket liker vi ikke det faktum at man1.equals(man2) i hovedsak er ekvivalent med man1 == man2 . Her er hva vi skal gjøre i denne situasjonen:

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

   } 
} 
Konsollutgang: sant Nå får vi et helt annet resultat! Ved å skrive vår egen equals()- metode og bruke den i stedet for standardmetoden, har vi produsert riktig oppførsel: Hvis to personer har samme DNA, rapporterer programmet "DNA-analyse har bevist at de er tvillinger" og returnerer sant! Ved å overstyre equals() -metoden i klassene dine, kan du enkelt lage den logikken du trenger for objektsammenligning. Faktisk har vi bare så vidt berørt objektsammenligning. Foran oss er det fortsatt en stor frittstående leksjon om dette emnet (du skumles over det nå hvis du er interessert).

Sammenligning av strenger i Java

Hvorfor vurderer vi strengsammenligninger separat fra alt annet? Realiteten er at strenger er et emne i seg selv i programmering. For det første, hvis du tar alle Java-programmene som noen gang er skrevet, vil du finne at omtrent 25 % av objektene i dem er strenger. Så dette temaet er veldig viktig. For det andre er prosessen med å sammenligne strenger veldig forskjellig fra andre objekter. Tenk på et enkelt eksempel:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Konsollutgang: falsk Men hvorfor fikk vi falsk? Tross alt er strengene nøyaktig de samme, ord for ord :/ Du har kanskje gjettet årsaken: det er fordi ==- operatoren sammenligner referanser ! Det er klart at s1 og s2 har forskjellige adresser i minnet. Hvis du tenkte på det, la oss omarbeide eksemplet vårt:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       System.out.println(s1 == s2);
   }
}
Nå har vi igjen to referanser, men resultatet er det stikk motsatte: Konsollutgang: sant Hjelpeløst forvirret? La oss finne ut hva som skjer. Operatoren == sammenligner virkelig minneadresser. Dette er alltid sant, og du trenger ikke å tvile på det. Det betyr at hvis s1 == s2 returnerer sann, så har disse to strengene samme adresse. Og dette er faktisk sant! Det er på tide å introdusere deg til et spesielt minneområde for lagring av strenger: strengebassenget
Lik og strengsammenligninger - 3
Strengebassenget er et område for lagring av alle strengverdiene du oppretter i programmet ditt. Hvorfor ble det opprettet? Som vi sa før, representerer strenger en stor prosentandel av alle objekter. Ethvert stort program lager mange strenger. Strengepoolen ble opprettet for å spare minne: strenger plasseres der og deretter opprettede strenger refererer til det samme minneområdet – det er ikke nødvendig å tildele ekstra minne hver gang. Hver gang du skriver String = "........" sjekker programmet om det er en identisk streng i strengpoolen. Hvis det er det, vil det ikke bli opprettet en ny streng. Og den nye referansen vil peke til den samme adressen i strengpoolen (hvor den identiske strengen er plassert). Så da vi skrev

String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 peker på samme sted som s1 . Den første setningen oppretter en ny streng i strengpoolen. Den andre setningen refererer ganske enkelt til det samme minneområdet som s1 . Du kan lage ytterligere 500 identiske strenger og resultatet vil ikke endre seg. Vent litt. Hvis det er sant, hvorfor fungerte da ikke dette eksemplet før?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
Jeg tror din intuisjon allerede har fortalt deg årsaken =) Prøv å gjett før du leser videre. Du kan se at disse to strengene ble erklært på forskjellige måter. Den ene med den nye operatøren, og den andre uten. Her ligger årsaken. Når den nye operatoren brukes til å lage et objekt, tildeler den et nytt minneområde for objektet. Og en streng opprettet ved hjelp av ny havner ikke i strengpoolen - den blir et separat objekt, selv om teksten samsvarer perfekt med en streng i strengpoolen. Det vil si hvis vi skriver følgende kode:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       String s3 = new String("CodeGym is the best website for learning Java!");
   }
}
I minnet ser det slik ut:
Lik og strengsammenligninger - 4
Og hver gang du oppretter et nytt objekt ved å bruke new , tildeles et nytt minneområde, selv om teksten i den nye strengen er den samme! Det ser ut til at vi har funnet ut operatoren == . Men hva med vårt nye bekjentskap, equals() -metoden?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1.equals(s2));
   }
}
Konsollutgang: sant Interessant. Vi er sikre på at s1 og s2 peker på forskjellige områder i minnet. Men equals()- metoden forteller oss fortsatt at de er like. Hvorfor? Husk at vi tidligere sa at equals()- metoden kan overstyres for å sammenligne objekter slik vi vil? Det er akkurat det de har gjort med String -klassen. Den overstyrer lik ()metode. Og i stedet for å sammenligne referanser, sammenligner den sekvensen av tegn i strengene. Hvis teksten er den samme, spiller det ingen rolle hvordan de ble opprettet eller hvor de er lagret: enten i strengpoolen eller et eget minneområde. Resultatet av sammenligningen vil være sant. Java lar deg forresten utføre sammenligninger av strenger som ikke skiller mellom store og små bokstaver. Normalt, hvis en av strengene har alle store bokstaver, vil resultatet av sammenligningen være usant:

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CODEGYM IS THE BEST WEBSITE FOR LEARNING JAVA!");
       System.out.println(s1.equals(s2));
   }
}
Konsollutdata: false For sammenligninger som ikke skiller mellom store og små bokstaver, har String- klassen metoden equalsIgnoreCase() . Du kan bruke den hvis du bare bryr deg om å sammenligne sekvensen av spesifikke tegn i stedet for store og små bokstaver. Dette kan for eksempel være nyttig når du sammenligner to adresser:

public class Main {

   public static void main(String[] args) {

       String address1 = "2311 Broadway Street, San Francisco";
       String address2 = new String("2311 BROADWAY STREET, SAN FRANCISCO");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
I dette tilfellet snakker vi åpenbart om samme adresse, så det er fornuftig å bruke equalsIgnoreCase()- metoden.

String.intern()-metoden

String - klassen har en mer vanskelig metode: intern() ; Intern () -metoden fungerer direkte med strengpoolen. Hvis du kaller intern() -metoden på en streng:
  • Den sjekker om det er en samsvarende streng i strengbassenget
  • Hvis det er det, returnerer den referansen til strengen i bassenget
  • Hvis ikke, legger den til strengen til strengpoolen og returnerer en referanse til den.
Etter å ha brukt intern() -metoden på en strengreferanse oppnådd med new , kan vi bruke ==- operatoren for å sammenligne den med en strengreferanse fra strengpoolen.

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2.intern());
   }
}
Konsollutgang: true Når vi sammenlignet disse strengene tidligere uten intern() , var resultatet usant. Nå sjekker intern() -metoden om strengen "CodeGym er den beste siden for å lære Java!" er i strengebassenget. Selvfølgelig er det det: vi skapte det med

String s1 = "CodeGym is the best website for learning Java!";
Vi sjekker om s1 og referansen returnert av s2.intern() peker til samme minneområde. Og selvfølgelig gjør de det :) Oppsummert, husk og bruk denne viktige regelen: Bruk ALLTID equals()- metoden for å sammenligne strenger! Når vi sammenligner strenger, mener vi nesten alltid å sammenligne karakterene deres i stedet for referanser, minneområder eller noe annet. equals ()- metoden gjør akkurat det du trenger. For å forsterke det du lærte, foreslår vi at du ser en videoleksjon fra vårt Java-kurs
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION