CodeGym/Java-Blog/Random-DE/Vergleichen Sie String- und Equals-Vergleiche in Java
Autor
Milan Vucic
Programming Tutor at Codementor.io

Vergleichen Sie String- und Equals-Vergleiche in Java

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute werden wir über ein sehr wichtiges und interessantes Thema sprechen, nämlich den Vergleich von Objekten mit Objekten (Compare Strings and Equals). Wann genau wäre in Java Objekt A gleich Objekt B ? Versuchen wir, ein Beispiel zu schreiben:
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);
   }
}
Konsolenausgabe: false. Warten, stoppen. Warum sind diese beiden Autos nicht gleich? Wir haben ihnen die gleichen Eigenschaften zugewiesen, aber das Ergebnis des Vergleichs ist falsch. Die Antwort ist einfach. Der ==- Operator vergleicht Objektreferenzen, nicht Objekteigenschaften. Zwei Objekte könnten sogar 500 Felder mit identischen Werten haben, aber ein Vergleich würde immer noch „false“ ergeben. Immerhin Referenzen car1 und car2zeigen auf zwei verschiedene Objekte, also auf zwei verschiedene Adressen. Stellen Sie sich eine Situation vor, in der Sie Menschen vergleichen. Sicher gibt es irgendwo auf der Welt eine Person, die den gleichen Namen, die gleiche Augenfarbe, das gleiche Alter, die gleiche Größe, die gleiche Haarfarbe usw. hat. Das macht euch in vielerlei Hinsicht ähnlich, aber ihr seid immer noch keine Zwillinge – und das seid ihr ganz offensichtlich nicht die selbe Person.
Gleichheits- und Zeichenfolgenvergleiche - 2
Der ==- Operator verwendet ungefähr dieselbe Logik, wenn wir ihn zum Vergleichen zweier Objekte verwenden. Was aber, wenn Ihr Programm eine andere Logik verwenden soll? Angenommen, Ihr Programm führt eine DNA-Analyse durch. Es vergleicht den genetischen Code zweier Menschen und stellt fest, ob es sich um Zwillinge handelt.
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);
   }
}
Konsolenausgabe: false Wir erhalten das gleiche logische Ergebnis (weil wir nicht viel geändert haben), aber jetzt ist diese Logik nicht mehr gut! Schließlich sollte uns die DNA-Analyse im wirklichen Leben eine 100-prozentige Garantie geben, dass wir Zwillinge vor uns haben. Aber unser Programm und der ==- Operator sagen uns das Gegenteil. Wie ändern wir dieses Verhalten und stellen sicher, dass das Programm das richtige Ergebnis ausgibt, wenn die DNA übereinstimmt? Java hat dafür eine spezielle Methode: equal() . Wie die toString()- Methode, die wir zuvor besprochen haben, gehört equal() zur Object- Klasse – der wichtigsten Klasse in Java, der Klasse, von der alle anderen Klassen abgeleitet sind. Aber gleich()ändert das Verhalten unseres Programms nicht von alleine:
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));
   }
}
Konsolenausgabe: false. Genau das gleiche Ergebnis. Wozu brauchen wir diese Methode? :/ Es ist alles einfach. Das Problem hierbei ist, dass wir diese Methode derzeit so verwenden, wie sie in der Object- Klasse implementiert ist. Und wenn wir uns den Code der Object- Klasse ansehen und uns die Implementierung der Methode ansehen, sehen wir Folgendes:
public boolean equals(Object obj) {
   return (this == obj);
}
Aus diesem Grund hat sich das Verhalten des Programms nicht geändert! Derselbe Operator == (der Referenzen vergleicht) wird in der Methode equal() der Klasse Object verwendet . Der Trick bei dieser Methode besteht jedoch darin, dass wir sie überschreiben können. Überschreiben bedeutet, dass Sie Ihre eigene equal()- Methode in unserer Man- Klasse schreiben und ihr so ​​das Verhalten verleihen, das wir brauchen! Derzeit gefällt uns die Tatsache nicht, dass man1.equals(man2) im Wesentlichen äquivalent zu man1 == man2 ist . Folgendes werden wir in dieser Situation tun:
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));

   }
}
Konsolenausgabe: true Jetzt erhalten wir ein völlig anderes Ergebnis! Indem wir unsere eigene equal()- Methode geschrieben und diese anstelle der Standardmethode verwendet haben, haben wir das richtige Verhalten erzeugt: Wenn nun zwei Personen dieselbe DNA haben, meldet das Programm „DNA-Analyse hat bewiesen, dass es sich um Zwillinge handelt“ und gibt „true“ zurück! Indem Sie die Methode equal() in Ihren Klassen überschreiben , können Sie ganz einfach jede benötigte Objektvergleichslogik erstellen. Tatsächlich haben wir den Objektvergleich gerade erst angesprochen. Vor uns liegt noch eine große eigenständige Lektion zu diesem Thema (Sie können sie jetzt überfliegen, wenn Sie interessiert sind).

Vergleichen von Zeichenfolgen in Java

Warum betrachten wir Stringvergleiche getrennt von allem anderen? Die Realität ist, dass Strings ein eigenständiges Thema in der Programmierung sind. Wenn Sie zunächst alle jemals geschriebenen Java-Programme betrachten, werden Sie feststellen, dass etwa 25 % der darin enthaltenen Objekte Zeichenfolgen sind. Daher ist dieses Thema sehr wichtig. Zweitens unterscheidet sich der Prozess des Vergleichs von Zeichenfolgen wirklich stark von dem Vergleich anderer Objekte. Betrachten Sie ein einfaches Beispiel:
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);
   }
}
Konsolenausgabe: false Aber warum haben wir false erhalten? Schließlich sind die Zeichenfolgen Wort für Wort genau gleich :/ Sie haben vielleicht den Grund erraten: Es liegt daran, dass der ==- Operator Referenzen vergleicht ! Offensichtlich haben s1 und s2 unterschiedliche Adressen im Speicher. Wenn Ihnen das eingefallen ist, überarbeiten wir unser Beispiel noch einmal:
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);
   }
}
Jetzt haben wir wieder zwei Referenzen, aber das Ergebnis ist genau das Gegenteil: Konsolenausgabe: true Hilflos verwirrt? Lassen Sie uns herausfinden, was los ist. Der ==- Operator vergleicht tatsächlich Speicheradressen. Das ist immer wahr und Sie müssen nicht daran zweifeln. Das heißt, wenn s1 == s2 „true“ zurückgibt, dann haben diese beiden Zeichenfolgen dieselbe Adresse. Und das stimmt tatsächlich! Es ist an der Zeit, Ihnen einen speziellen Speicherbereich zum Speichern von Strings vorzustellen: den String-Pool
Gleichheits- und Zeichenfolgenvergleiche - 3
Der String-Pool ist ein Bereich zum Speichern aller String-Werte, die Sie in Ihrem Programm erstellen. Warum wurde es geschaffen? Wie bereits erwähnt, machen Strings einen großen Prozentsatz aller Objekte aus. Jedes große Programm erstellt viele Zeichenfolgen. Der String-Pool wurde erstellt, um Speicher zu sparen: Strings werden dort abgelegt und anschließend erstellte Strings beziehen sich auf denselben Speicherbereich – es ist nicht erforderlich, jedes Mal zusätzlichen Speicher zuzuweisen. Jedes Mal, wenn Sie String = „........“ schreiben , prüft das Programm, ob sich im String-Pool ein identischer String befindet. Wenn dies der Fall ist, wird keine neue Zeichenfolge erstellt. Und die neue Referenz zeigt auf dieselbe Adresse im String-Pool (wo sich der identische String befindet). Als wir also schrieben
String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 zeigt auf die gleiche Stelle wie s1 . Die erste Anweisung erstellt eine neue Zeichenfolge im Zeichenfolgenpool. Die zweite Anweisung bezieht sich einfach auf denselben Speicherbereich wie s1 . Sie könnten weitere 500 identische Zeichenfolgen erstellen und das Ergebnis würde sich nicht ändern. Warten Sie eine Minute. Wenn das stimmt, warum hat dieses Beispiel dann vorher nicht funktioniert?
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);
   }
}
Ich denke, Ihre Intuition hat Ihnen den Grund bereits verraten =) Versuchen Sie es zu erraten, bevor Sie weiterlesen. Sie können sehen, dass diese beiden Zeichenfolgen auf unterschiedliche Weise deklariert wurden. Einer mit dem neuen Operator und der andere ohne. Hierin liegt der Grund. Wenn der neue Operator zum Erstellen eines Objekts verwendet wird, wird dem Objekt zwangsweise ein neuer Speicherbereich zugewiesen. Und ein mit new erstellter String landet nicht im String-Pool – er wird zu einem separaten Objekt, selbst wenn sein Text perfekt mit einem String im String-Pool übereinstimmt. Das heißt, wenn wir den folgenden Code schreiben:
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!");
   }
}
In der Erinnerung sieht es so aus:
Gleichheits- und Zeichenfolgenvergleiche - 4
Und jedes Mal, wenn Sie mit new ein neues Objekt erstellen , wird ein neuer Speicherbereich zugewiesen, auch wenn der Text in der neuen Zeichenfolge derselbe ist! Anscheinend haben wir den ==- Operator herausgefunden . Aber was ist mit unserer neuen Bekanntschaft, der Methode equal() ?
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));
   }
}
Konsolenausgabe: wahr. Interessant. Wir sind sicher, dass s1 und s2 auf unterschiedliche Bereiche im Speicher verweisen. Aber die Methode equal() sagt uns immer noch, dass sie gleich sind. Warum? Erinnern Sie sich, dass wir zuvor gesagt haben, dass die Methode equal() überschrieben werden kann, um Objekte nach Belieben zu vergleichen? Genau das haben sie mit der String- Klasse gemacht. Es überschreibt equal()Methode. Und anstatt Referenzen zu vergleichen, wird die Zeichenfolge in den Zeichenfolgen verglichen. Wenn der Text derselbe ist, spielt es keine Rolle, wie er erstellt wurde oder wo er gespeichert ist: ob im String-Pool oder in einem separaten Speicherbereich. Das Ergebnis des Vergleichs wird wahr sein. Übrigens können Sie mit Java Zeichenfolgenvergleiche ohne Berücksichtigung der Groß-/Kleinschreibung durchführen. Wenn eine der Zeichenfolgen ausschließlich aus Großbuchstaben besteht, ist das Ergebnis des Vergleichs normalerweise falsch:
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));
   }
}
Konsolenausgabe: false Für Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung verfügt die String- Klasse über die Methode equalIgnoreCase() . Sie können es verwenden, wenn Sie nur die Reihenfolge bestimmter Zeichen und nicht die Groß-/Kleinschreibung vergleichen möchten. Dies könnte beispielsweise beim Vergleich zweier Adressen hilfreich sein:
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));
   }
}
In diesem Fall handelt es sich offensichtlich um dieselbe Adresse, daher ist es sinnvoll, die Methode equalIgnoreCase() zu verwenden.

Die String.intern()-Methode

Die String- Klasse verfügt über eine weitere knifflige Methode: intern() ; Die Methode intern() arbeitet direkt mit dem String-Pool. Wenn Sie die intern() -Methode für eine Zeichenfolge aufrufen :
  • Es prüft, ob im String-Pool ein passender String vorhanden ist
  • Wenn dies der Fall ist, wird der Verweis auf die Zeichenfolge im Pool zurückgegeben
  • Wenn nicht, fügt es die Zeichenfolge dem Zeichenfolgenpool hinzu und gibt einen Verweis darauf zurück.
Nachdem wir die Methode intern() auf eine mit new erhaltene String-Referenz angewendet haben , können wir sie mit dem Operator == mit einer String-Referenz aus dem String-Pool vergleichen.
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());
   }
}
Konsolenausgabe: true Als wir diese Zeichenfolgen zuvor ohne intern() verglichen haben , war das Ergebnis falsch. Nun prüft die Methode intern() , ob die Zeichenfolge „CodeGym ist die beste Seite zum Erlernen von Java!“ enthalten ist. befindet sich im String-Pool. Natürlich ist es so: Wir haben es mit erstellt
String s1 = "CodeGym is the best website for learning Java!";
Wir prüfen, ob s1 und die von s2.intern() zurückgegebene Referenz auf denselben Speicherbereich verweisen. Und das tun sie natürlich :) Zusammenfassend sollten Sie sich diese wichtige Regel merken und anwenden: Verwenden Sie IMMER die Methode equal() , um Zeichenfolgen zu vergleichen! Beim Vergleich von Zeichenfolgen geht es fast immer um den Vergleich ihrer Zeichen und nicht um Referenzen, Speicherbereiche oder irgendetwas anderes. Die Methode equal() macht genau das, was Sie brauchen. Um das Gelernte zu vertiefen, empfehlen wir Ihnen, sich eine Videolektion aus unserem Java-Kurs anzusehen

Mehr Lektüre:

Kommentare
  • Beliebt
  • Neu
  • Alt
Du musst angemeldet sein, um einen Kommentar schreiben zu können
Auf dieser Seite gibt es noch keine Kommentare