CodeGym /Java blog /Tilfældig /Sammenlign String og Equals sammenligninger i Java
John Squirrels
Niveau
San Francisco

Sammenlign String og Equals sammenligninger i Java

Udgivet i gruppen
Hej! I dag vil vi tale om et meget vigtigt og interessant emne, nemlig at sammenligne objekter med objekter (Sammenlign strenge og lig). Så i Java, hvornår præcist ville objekt A være lig med objekt B ? Lad os prøve at 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);
   }
}
Konsoludgang: falsk Vent, stop. Hvorfor er det, at disse to biler ikke er lige? Vi tildelte dem de samme egenskaber, men resultatet af sammenligningen er falsk. Svaret er enkelt. Operatoren == sammenligner objektreferencer, ikke objektegenskaber. To objekter kunne endda have 500 felter med identiske værdier, men at sammenligne dem ville stadig give falsk. Referencer jo bil1 og bil2pege på to forskellige objekter, altså på to forskellige adresser. Forestil dig en situation, hvor du sammenligner mennesker. Bestemt, et sted i verden er der en person, der deler dit samme navn, øjenfarve, alder, højde, hårfarve osv. Det gør dig ens i mange henseender, men du er stadig ikke tvillinger - og du er åbenbart ikke samme person.
Lige og strenge sammenligninger - 2
Operatoren == bruger omtrent den samme logik, når vi bruger den til at sammenligne to objekter. Men hvad hvis du har brug for, at dit program bruger en anden logik? Antag for eksempel, at dit program udfører DNA-analyse. Den sammenligner den genetiske kode for to mennesker og afgø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);
   }
}
Konsoloutput: falsk Vi får det samme logiske resultat (fordi vi ikke har ændret meget), men nu er den logik ikke god! Når alt kommer til alt, i det virkelige liv burde DNA-analyse give os en 100 % garanti for, at vi har tvillinger stående foran os. Men vores program og ==- operatøren fortæller os det modsatte. Hvordan ændrer vi denne adfærd og sikrer, at programmet udsender det korrekte resultat, når DNA'et matcher? Java har en speciel metode til dette: equals() . Ligesom toString()- metoden, som vi diskuterede tidligere, tilhører equals() klassen Object — den vigtigste klasse i Java, klassen som alle andre klasser stammer fra. Men lig med()ændrer ikke vores programs adfærd helt af sig 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));
   }
}
Konsoloutput: falsk Præcis det samme resultat, så hvad skal vi bruge denne metode til? :/ Det hele er simpelt. Problemet her er, at vi i øjeblikket bruger denne metode, da den er implementeret i Object- klassen. Og hvis vi går ind i koden for Object- klassen og ser på metodens implementering, er dette, hvad vi vil se:

public boolean equals(Object obj) {
   return (this == obj);
}
Det er grunden til, at programmets adfærd ikke har ændret sig! Den samme ==- operator (som sammenligner referencer) bruges i equals()- metoden i Object- klassen. Men tricket med denne metode er, at vi kan tilsidesætte den. At tilsidesætte betyder at skrive din egen equals()- metode i vores Man- klasse, hvilket giver den den adfærd, vi har brug for! På nuværende tidspunkt bryder vi os ikke om, at man1.equals(man2) i det væsentlige svarer til man1 == man2 . Her er, hvad vi vil gøre i denne situation:

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

   } 
} 
Konsoloutput: sandt Nu får vi et helt andet resultat! Ved at skrive vores egen equals()- metode og bruge den i stedet for standardmetoden, har vi produceret den korrekte adfærd: Hvis to personer nu har det samme DNA, rapporterer programmet "DNA-analyse har bevist, at de er tvillinger" og returnerer sandt! Ved at tilsidesætte equals() -metoden i dine klasser, kan du nemt oprette den objektsammenligningslogik, du har brug for. Faktisk har vi kun lige berørt objektsammenligning. Foran os er der stadig en stor selvstændig lektion om dette emne (du skimmer over det nu, hvis du er interesseret).

Sammenligning af strenge i Java

Hvorfor overvejer vi strengsammenligninger adskilt fra alt andet? Virkeligheden er, at strenge er et emne i sig selv i programmering. For det første, hvis du tager alle de Java-programmer, der nogensinde er skrevet, vil du opdage, at omkring 25 % af objekterne i dem er strenge. Så dette emne er meget vigtigt. For det andet er processen med at sammenligne strenge virkelig meget forskellig fra andre objekter. Overvej et simpelt 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);
   }
}
Konsoloutput: falsk Men hvorfor fik vi falsk? Strengene er trods alt nøjagtig de samme, ord for ord :/ Du har måske gættet årsagen: det er fordi == operatoren sammenligner referencer ! Det er klart, at s1 og s2 har forskellige adresser i hukommelsen. Hvis du tænkte på det, så lad os omarbejde vores eksempel:

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);
   }
}
Nu har vi igen to referencer, men resultatet er det stik modsatte: Konsol output: sand Hjælpeløst forvirret? Lad os finde ud af, hvad der foregår. Operatoren == sammenligner virkelig hukommelsesadresser. Dette er altid sandt, og du behøver ikke at tvivle på det. Det betyder, at hvis s1 == s2 returnerer sand, så har disse to strenge den samme adresse. Og det er sandelig sandt! Det er tid til at introducere dig til et særligt hukommelsesområde til lagring af strenge: strengepuljen
Lige og strenge sammenligninger - 3
Strengepuljen er et område til lagring af alle de strengværdier, du opretter i dit program. Hvorfor blev det skabt? Som vi sagde før, repræsenterer strenge en enorm procentdel af alle objekter. Ethvert stort program skaber en masse strenge. Strengpuljen blev oprettet for at spare hukommelse: strenge placeres der, og efterfølgende oprettede strenge refererer til det samme hukommelsesområde - der er ingen grund til at allokere yderligere hukommelse hver gang. Hver gang du skriver String = "........" tjekker programmet, om der er en identisk streng i strengpuljen. Hvis der er, vil der ikke blive oprettet en ny streng. Og den nye reference vil pege på den samme adresse i strengpuljen (hvor den identiske streng er placeret). 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 peger på samme sted som s1 . Den første sætning opretter en ny streng i strengpuljen. Den anden sætning refererer simpelthen til det samme hukommelsesområde som s1 . Du kan lave yderligere 500 identiske strenge, og resultatet ville ikke ændre sig. Vent et øjeblik. Hvis det er sandt, hvorfor virkede dette eksempel så ikke 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 intuition allerede har fortalt dig årsagen =) Prøv at gætte, før du læser videre. Du kan se, at disse to strenge blev erklæret på forskellige måder. Den ene med den nye operatør, og den anden uden. Heri ligger årsagen. Når den nye operator bruges til at oprette et objekt, tildeler den med kraft et nyt hukommelsesområde til objektet. Og en streng, der er oprettet ved hjælp af ny , ender ikke i strengpuljen - den bliver et separat objekt, selvom dens tekst passer perfekt til en streng i strengpuljen. Det vil sige, 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 hukommelsen ser det sådan ud:
Lige og strenge sammenligninger - 4
Og hver gang du opretter et nyt objekt ved hjælp af new , tildeles et nyt hukommelsesområde, selvom teksten inde i den nye streng er den samme! Det ser ud til, at vi har fundet ud af ==- operatoren. Men hvad med vores nye bekendtskab, 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));
   }
}
Konsoloutput: sandt Interessant. Vi er sikre på, at s1 og s2 peger på forskellige områder i hukommelsen. Men equals()- metoden fortæller os stadig, at de er lige. Hvorfor? Husk, at vi tidligere sagde, at equals()- metoden kunne tilsidesættes for at sammenligne objekter, som vi vil? Det er bare, hvad de har gjort med String -klassen. Det tilsidesætter lig ()metode. Og i stedet for at sammenligne referencer, sammenligner den rækkefølgen af ​​tegn i strengene. Hvis teksten er den samme, er det ligegyldigt, hvordan de blev oprettet, eller hvor de er gemt: om det er i strengpuljen eller et separat hukommelsesområde. Resultatet af sammenligningen vil være sandt. Java giver dig i øvrigt mulighed for at udføre sammenligninger mellem store og små bogstaver. Normalt, hvis en af ​​strengene har alle store bogstaver, vil resultatet af sammenligningen være falsk:

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));
   }
}
Konsoloutput: false For sammenligninger, der ikke skelner mellem store og små bogstaver, har String -klassen metoden equalsIgnoreCase() . Du kan bruge det, hvis du kun interesserer dig for at sammenligne rækkefølgen af ​​specifikke tegn i stedet for store og små bogstaver. Dette kan f.eks. være nyttigt, 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 tilfælde taler vi naturligvis om den samme adresse, så det giver mening at bruge equalsIgnoreCase() metoden.

String.intern() metoden

String - klassen har endnu en vanskelig metode: intern() ; Intern () -metoden fungerer direkte med strengpuljen. Hvis du kalder intern() metoden på en streng:
  • Den tjekker, om der er en matchende streng i strengpuljen
  • Hvis der er, returnerer den referencen til strengen i puljen
  • Hvis ikke, tilføjer den strengen til strengpuljen og returnerer en reference til den.
Efter at have brugt intern() metoden på en strengreference opnået ved hjælp af new , kan vi bruge == operatoren til at sammenligne den med en strengreference fra strengpuljen.

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());
   }
}
Konsoloutput: sand Da vi tidligere sammenlignede disse strenge uden intern() , var resultatet falsk. Nu kontrollerer intern() metoden, om strengen "CodeGym er det bedste sted at lære Java!" er i strygebassinet. Selvfølgelig er det det: vi skabte det med

String s1 = "CodeGym is the best website for learning Java!";
Vi kontrollerer om s1 og referencen returneret af s2.intern() peger på det samme hukommelsesområde. Og selvfølgelig gør de det :) Sammenfattende skal du huske og anvende denne vigtige regel: Brug ALTID equals()- metoden til at sammenligne strenge! Når vi sammenligner strenge, mener vi næsten altid at sammenligne deres karakterer i stedet for referencer, hukommelsesområder eller noget andet. Metoden equals() gør præcis, hvad du har brug for. For at styrke det, du har lært, foreslår vi, at du ser en videolektion fra vores Java-kursus

Mere læsning:

Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION