EMZETT.
Login

Comparison Operators

Kurz: Operatoren, die zwei Werte vergleichen und ein boolean (true/false) zurückgeben: == != < > <= >=.

Genauer: Wichtige Falle in Java: == vergleicht bei Objekten (z. B. String) die Referenz, nicht den Inhalt — zwei inhaltlich gleiche Strings können mit == trotzdem false liefern, wenn es unterschiedliche Objekte im Speicher sind. Für den Inhaltsvergleich von Objekten gehört stattdessen .equals() genutzt.

Im Detail

String a = "hallo";
String b = "hallo";
String c = new String("hallo");
 
System.out.println(a == b);        // true - Java "internt" gleiche String-Literale automatisch
System.out.println(a == c);        // false - c ist ein eigenständiges Objekt im Heap
System.out.println(a.equals(c));   // true - Inhaltsvergleich, unabhängig von der Objektidentität
 
Integer x = 127, y = 127;
Integer p = 200, q = 200;
System.out.println(x == y); // true - Integer-Cache für -128..127
System.out.println(p == q); // false! Außerhalb des Caches sind es unterschiedliche Objekte

Der Integer-Cache-Fall ist besonders tückisch: Java cacht automatisch Integer-Objekte für kleine Werte (-128 bis 127) aus Performancegründen, wodurch ==-Vergleiche in diesem Bereich zufällig “funktionieren”, außerhalb aber nicht — ein klassischer Bug, der in Tests mit kleinen Zahlen unentdeckt bleibt und erst in Produktion mit größeren Werten auffällt. Faustregel ohne Ausnahmen: bei primitiven Typen (int, double, boolean, …) ist == korrekt und der einzig mögliche Vergleich; bei Objekten (String, Integer, eigene Klassen, …) immer .equals() nutzen, nie ==.

Relationale Operatoren bei verschiedenen Typen

< > <= >= funktionieren in Java nur auf primitiven Zahlentypen (int, double, char, …), NICHT direkt auf Objekten wie String — "apfel" < "banane" kompiliert schlicht nicht. Für den lexikografischen Vergleich von Strings gibt es stattdessen compareTo():

String a = "apfel", b = "banane";
System.out.println(a.compareTo(b)); // negativ, da "apfel" alphabetisch vor "banane" kommt
System.out.println(a.compareTo(a)); // 0 - identisch

Das Vorzeichen des Rückgabewerts zählt, nicht der exakte Zahlenwert — negativ bedeutet “kommt vorher”, positiv “kommt nachher”, 0 bedeutet “gleich”. Dieses compareTo()-Muster zieht sich durch ganz Java: das Comparable-Interface (für die “natürliche” Sortierreihenfolge einer Klasse) und Comparator (für benutzerdefinierte Sortierreihenfolgen) bauen beide genau darauf auf.

equals() selbst überschreiben

Bei eigenen Klassen liefert .equals() ohne eigene Implementierung standardmäßig dasselbe Ergebnis wie == (Referenzvergleich), da Object.equals() genau das tut. Für einen echten Inhaltsvergleich muss equals() (und aus Konsistenzgründen immer auch hashCode()) überschrieben werden:

class Punkt {
    int x, y;
 
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Punkt p)) return false;
        return x == p.x && y == p.y;
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

Wird equals() überschrieben, aber hashCode() vergessen (oder umgekehrt), verhalten sich HashSet/HashMap inkonsistent — zwei laut equals() gleiche Objekte können dann trotzdem als “verschieden” behandelt werden, weil sie unterschiedliche Hash-Codes haben.

Siehe auch: Operatoren, Logical Operators, if-Statement