CodeGym /Java blog /Véletlen /Hasonlítsa össze a String és az Equals összehasonlításoka...
John Squirrels
Szint
San Francisco

Hasonlítsa össze a String és az Equals összehasonlításokat Java nyelven

Megjelent a csoportban
Szia! Ma egy nagyon fontos és érdekes témáról fogunk beszélni, nevezetesen az objektumok objektumokkal való összehasonlításáról (Strings and Equals összehasonlítása). Tehát Java-ban pontosan mikor lenne egyenlő az A objektum a B objektummal ? Próbáljunk meg egy példát írni:

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);
   }
}
Konzol kimenet: false Várj, állj. Miért nem egyenlő ez a két autó? Ugyanazokat a tulajdonságokat rendeltük hozzájuk, de az összehasonlítás eredménye hamis. A válasz egyszerű. Az == operátor objektumhivatkozásokat hasonlít össze, nem objektumtulajdonságokat. Két objektum akár 500 azonos értékű mezőt is tartalmazhat, de összehasonlításuk továbbra is hamis eredményt adna. Végül is az autó1 és az autó2 hivatkozásokmutasson két különböző objektumra, azaz két különböző címre. Képzeljen el egy olyan helyzetet, amikor összehasonlítja az embereket. Valahol a világon van egy személy, akinek ugyanaz a neve, szemszíne, életkora, magassága, hajszíne stb. Ez sok tekintetben hasonlóvá tesz benneteket, de még mindig nem vagytok ikrek – és nyilvánvalóan nem vagytok azok. ugyanaz a személy.
Egyenlő és karakterlánc-összehasonlítás - 2
Az == operátor megközelítőleg ugyanezt a logikát használja, amikor két objektumot hasonlítunk össze. De mi van akkor, ha a programodban más logikát kell használni? Tegyük fel például, hogy a program DNS-elemzést végez. Összehasonlítja két ember genetikai kódját, és meghatározza, hogy ikrek-e.

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);
   }
}
Konzol kimenet: false Ugyanazt a logikai eredményt kapjuk (mert nem sokat változtattunk), de most ez a logika nem jó! Végül is a való életben a DNS-elemzésnek 100%-os garanciát kell adnia arra, hogy ikrek állnak előttünk. De a programunk és az == operátor ennek az ellenkezőjét állítja. Hogyan változtathatjuk meg ezt a viselkedést, és győződjön meg arról, hogy a program a megfelelő eredményt adja ki, ha a DNS egyezik? A Java-nak van erre egy speciális metódusa: equals() . A toString() metódushoz hasonlóan, amelyről korábban beszéltünk, az equals() az Object osztályhoz tartozik – a Java legfontosabb osztályához, amelyből az összes többi osztály származik. De egyenlő ()önmagában nem változtatja meg programunk viselkedését:

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));
   }
}
Konzol kimenet: false Pontosan ugyanaz az eredmény, akkor mire van szükségünk erre a módszerre? :/ Egyszerű az egész. A probléma az, hogy jelenleg ezt a metódust használjuk, ahogyan az Object osztályban van megvalósítva. És ha belemegyünk az Object osztály kódjába, és megnézzük a metódus megvalósítását, akkor ezt fogjuk látni:

public boolean equals(Object obj) {
   return (this == obj);
}
Ez az oka annak, hogy a program viselkedése nem változott! Ugyanaz az == operátor (ami a hivatkozásokat hasonlítja össze) az Object osztály equals() metódusán belül használatos . De ezzel a módszerrel az a trükk, hogy felülírhatjuk. A felülbírálás azt jelenti, hogy a Man osztályunkba beírod a saját equals() metódusodat , megadva neki a szükséges viselkedést! Jelenleg nem szeretjük, hogy man1.egyenlő(man2) lényegében ekvivalens man1 == ember2 . Íme, mit fogunk tenni ebben a helyzetben:

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

   } 
} 
Konzol kimenet: igaz Most egészen más eredményt kapunk! A saját equals() metódusunk felírásával és a szokásos helyett azt használva a helyes viselkedést produkáltuk: Ha két embernek ugyanaz a DNS-e, akkor a program azt jelenti, hogy "A DNS-elemzés bebizonyította, hogy ikrek" és igazat ad vissza! Az osztályokban az equals() metódus felülbírálásával könnyedén létrehozhat bármilyen objektum-összehasonlítási logikát, amire szüksége van. Valójában csak most érintettük a tárgyak összehasonlítását. Előttünk van még egy nagy önálló lecke ebben a témában (ha érdekel, most lapozd át).

Stringek összehasonlítása Java nyelven

Miért vesszük figyelembe a karakterlánc-összehasonlításokat minden mástól elkülönítve? A valóság az, hogy a húrok önálló alanyok a programozásban. Először is, ha figyelembe vesszük az összes valaha írt Java programot, azt találjuk, hogy a bennük lévő objektumok körülbelül 25%-a karakterlánc. Tehát ez a téma nagyon fontos. Másodszor, a karakterláncok összehasonlításának folyamata nagyon különbözik a többi objektumtól. Vegyünk egy egyszerű példát:

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);
   }
}
Konzol kimenet: false De miért kaptunk falset? Hiszen a karakterláncok pontosan ugyanazok, szóról szóra :/ Az okot sejthetted: azért, mert az == operátor összehasonlítja a hivatkozásokat ! Nyilvánvaló, hogy s1 és s2 különböző címekkel rendelkezik a memóriában. Ha erre gondolt, dolgozzuk át a példánkat:

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);
   }
}
Most ismét van két hivatkozásunk, de az eredmény pont az ellenkezője: Konzol kimenet: igaz Tehetetlenül zavart? Találjuk ki, mi történik. Az == operátor valóban összehasonlítja a memóriacímeket. Ez mindig igaz, és nem kell kételkedned benne. Ez azt jelenti, hogy ha s1 == s2 igazat ad vissza, akkor ennek a két karakterláncnak ugyanaz a címe. És ez valóban igaz! Itt az ideje, hogy bemutassuk a memória egy speciális területét a karakterláncok tárolására: a húrkészletet
Egyenlő és karakterlánc-összehasonlítás - 3
A karakterlánckészlet a programban létrehozott összes karakterlánc-érték tárolására szolgáló terület. Miért jött létre? Mint korábban említettük, a karakterláncok az összes objektum nagy százalékát képviselik. Minden nagy program sok karakterláncot hoz létre. A karakterlánc-készletet a memória megtakarítása érdekében hozták létre: a karakterláncok ott vannak elhelyezve, majd a később létrehozott karakterláncok ugyanarra a memóriaterületre vonatkoznak – nincs szükség minden alkalommal további memóriát lefoglalni. Minden alkalommal, amikor beírja a String = "........" parancsot, a program ellenőrzi, hogy van-e azonos karakterlánc a karakterlánckészletben. Ha van, akkor nem jön létre új karakterlánc. És az új hivatkozás ugyanarra a címre fog mutatni a karakterlánc-készletben (ahol az azonos karakterlánc található). Tehát amikor írtunk

String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 ugyanoda mutat, mint s1 . Az első utasítás új karakterláncot hoz létre a karakterlánc-készletben. A második utasítás egyszerűen ugyanarra a memóriaterületre vonatkozik, mint az s1 . Újabb 500 azonos karakterláncot készíthet, és az eredmény nem változik. Várj egy percet. Ha ez igaz, akkor ez a példa miért nem működött korábban?

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);
   }
}
Azt hiszem, az intuíciója már megmondta az okot =) Próbáljon kitalálni, mielőtt tovább olvas. Látható, hogy ezt a két karakterláncot különböző módon deklarálták. Az egyik az új kezelővel, a másik pedig anélkül. Ebben rejlik az ok. Amikor az új operátort egy objektum létrehozására használjuk, az új memóriaterületet foglal le az objektum számára. A new használatával létrehozott karakterlánc pedig nem kerül a karakterlánc-készletbe – külön objektummá válik, még akkor is, ha a szövege tökéletesen megegyezik a karakterláncban lévő karakterlánccal. Vagyis ha a következő kódot írjuk:

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!");
   }
}
Emlékezetben így néz ki:
Egyenlő és karakterlánc-összehasonlítás - 4
És minden alkalommal, amikor új objektumot hoz létre a new használatával , új memóriaterület kerül lefoglalásra, még akkor is, ha az új karakterláncon belüli szöveg ugyanaz! Úgy tűnik, kitaláltuk az == operátort. De mi a helyzet új ismeretségünkkel, az equals() metódussal?

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));
   }
}
Konzol kimenet: igaz Érdekes. Biztosak vagyunk abban, hogy s1 és s2 különböző területekre mutat a memóriában. De az equals() metódus továbbra is azt mondja, hogy egyenlők. Miért? Emlékszel, korábban azt mondtuk, hogy az equals() metódus felülbírálható, hogy az objektumokat tetszőlegesen összehasonlíthassuk? Pont ezt tették a String osztállyal. Felülírja az egyenlőt()módszer. A hivatkozások összehasonlítása helyett pedig a karakterláncok karaktersorozatát hasonlítja össze. Ha a szöveg ugyanaz, akkor nem mindegy, hogy hogyan hozták létre, vagy hol tárolják: a karakterláncban vagy egy külön memóriaterületen. Az összehasonlítás eredménye igaz lesz. A Java egyébként lehetővé teszi a kis- és nagybetűk közötti karakterlánc-összehasonlításokat. Általában, ha az egyik karakterláncban csupa nagybetű van, akkor az összehasonlítás eredménye hamis lesz:

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));
   }
}
Konzol kimenete: false A kis- és nagybetűket nem érző összehasonlításokhoz a String osztály az equalsIgnoreCase() metódussal rendelkezik. Akkor használhatja, ha csak az egyes karakterek sorrendjét szeretné összehasonlítani, nem pedig a kis- és nagybetűket. Ez hasznos lehet például két cím összehasonlításakor:

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));
   }
}
Ebben az esetben nyilvánvalóan ugyanarról a címről beszélünk, ezért érdemes az equalsIgnoreCase() metódust használni.

A String.intern() metódus

A String osztálynak van még egy trükkös metódusa: intern() ; Az intern() metódus közvetlenül működik a karakterlánckészlettel. Ha meghívja az intern() metódust valamilyen karakterláncon:
  • Ellenőrzi, hogy van-e egyező karakterlánc a karakterlánckészletben
  • Ha van, akkor visszaadja a hivatkozást a készletben lévő karakterláncra
  • Ha nem, akkor hozzáadja a karakterláncot a karakterlánckészlethez, és visszaadja a hivatkozást.
Az intern() metódus használata után a new használatával kapott karakterlánc-hivatkozáson , az == operátorral összehasonlíthatjuk azt a karakterlánc-készletből származó karakterlánc-hivatkozással.

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());
   }
}
Konzol kimenete: true Ha ezeket a karakterláncokat korábban intern() nélkül hasonlítottuk össze , az eredmény false volt. Most az intern() metódus ellenőrzi, hogy a "CodeGym a legjobb hely a Java tanulásához!" a vonósmedencében van. Persze, hogy van: mi alkottuk meg

String s1 = "CodeGym is the best website for learning Java!";
Ellenőrizzük, hogy az s1 és az s2.intern() által visszaadott hivatkozás ugyanarra a memóriaterületre mutat-e. És persze meg is teszik :) Összefoglalva, jegyezze meg és alkalmazza ezt a fontos szabályt: MINDIG használd az equals() metódust a karakterláncok összehasonlításához! A karakterláncok összehasonlításakor szinte mindig a karaktereik összehasonlítására gondolunk, nem pedig hivatkozásokra, memóriaterületekre vagy bármi másra. Az equals() metódus pontosan azt csinálja, amire szüksége van. A tanultak megerősítése érdekében javasoljuk, hogy nézzen meg egy videóleckét a Java-tanfolyamról

További olvasnivalók:

Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION