Strings in Java: Warum `==` manchmal funktioniert und manchmal nicht

Julian | Jun 9, 2025 min read

Hallo zusammen,

heute tauchen wir in ein Java-Thema ein, das bei vielen Entwicklern, besonders am Anfang, für Kopfzerbrechen sorgt: Der Vergleich von Strings mit dem ==-Operator. Ihr habt sicherlich schon mal gehört, dass man Strings immer mit .equals() vergleichen sollte. Aber warum funktionieren dann die folgenden Tests, wenn wir doch == verwenden?

String a = "127";
String b = "127";
String c = "128";
String d = "128";

boolean comp = a == b;
boolean comp2 = a == c;
boolean comp3 = b == c;
boolean comp4 = c == d;

assertTrue(comp);
assertFalse(comp2);
assertFalse(comp3);
assertTrue(comp4);

Wenn ihr das in eurem Code ausprobiert, werdet ihr feststellen, dass alle assertTrue- und assertFalse-Statements erfolgreich sind. Aber wie kann das sein? Lasst uns das Mysterium lüften.

String Literale und der String Pool

Das Geheimnis liegt im String Pool (auch bekannt als String Intern Pool oder String Constant Pool). Dieser Pool ist ein spezieller Bereich im Heap-Speicher von Java, in dem String-Literale gespeichert werden.

Wenn die Java Virtual Machine (JVM) auf ein String-Literal (also einen String, der direkt im Code in doppelten Anführungszeichen steht, wie "127" oder "Hello") trifft, passiert Folgendes:

  1. Prüfung im String Pool: Die JVM prüft zuerst, ob ein String mit dem gleichen Wert bereits im String Pool existiert.
  2. Existiert er?
    • Ja: Wenn der String bereits existiert, wird einfach eine Referenz auf diesen bereits bestehenden String im Pool zurückgegeben. Es wird kein neuer String erzeugt.
    • Nein: Wenn der String noch nicht im Pool ist, wird ein neuer String im Pool erstellt und eine Referenz darauf zurückgegeben.

Die Magie hinter den Tests

Schauen wir uns eure Beispiele im Detail an:

String a = "127";
String b = "127";

Hier werden beide String-Literale auf den Wert "127" gesetzt. Da "127" ein String-Literal ist, wird die JVM zuerst prüfen, ob "127" bereits im String Pool ist. Da dies das erste Mal für diesen Wert ist, wird "127" im Pool angelegt, und sowohl a als auch b erhalten eine Referenz auf dasselbe String-Objekt im String Pool. Daher ist a == b * *true**.

String c = "128";
String d = "128";

Hier geschieht genau das Gleiche wie bei "127". Auch "128" ist ein String-Literal. Es wird im String Pool angelegt ( sofern nicht schon vorhanden), und c und d verweisen auf dasselbe Objekt im Pool. Deshalb ist c == d ebenfalls true.

Der Haken: Warum .equals() Standard sein sollte

Jetzt kommt der interessante Teil, der die Verwirrung oft erst richtig entstehen lässt:

boolean comp2 = a == c; // a="127", c="128"
boolean comp3 = b == c; // b="127", c="128"

In diesen Fällen vergleichen wir Referenzen auf unterschiedliche String-Literale. "127" und "128" sind natürlich zwei verschiedene Werte. Die JVM legt sie als separate Objekte im String Pool an. a und b verweisen auf das Objekt für "127", während c und d auf das Objekt für "128" verweisen. Da a (bzw. b) und c auf verschiedene Speicheradressen zeigen, ist der ==-Vergleich (der die Referenzen vergleicht) hier korrekt false.

Wann == nicht funktioniert

Der ==-Operator funktioniert nur dann zuverlässig für String-Vergleiche, wenn beide Strings als Literale im Code definiert sind und die JVM das String Interning anwendet. Sobald ein String auf andere Weise erzeugt wird, z.B. durch:

  • new String("Wert"): Hier wird explizit ein neues Objekt im Heap erzeugt, selbst wenn “Wert” bereits im String Pool ist. Die Referenz ist dann unterschiedlich.
  • String-Operationen: String result = str1 + str2; oder String result = str.substring(0, 3); erzeugen ebenfalls * neue String-Objekte* im Heap.

In diesen Fällen würden Vergleiche mit == fast immer false zurückgeben, auch wenn die String-Inhalte identisch wären.

String s1 = "Hallo";
String s2 = "Hallo";
String s3 = new String("Hallo");

System.out.println(s1 == s2); // true (beide Literale, gleiches Objekt im Pool)
System.out.println(s1 == s3); // false (s3 ist ein neues Objekt im Heap)
System.out.println(s1.equals(s3)); // true (Inhalte sind gleich)

Fazit

Die Beispiele zeigen, dass == für String-Literale funktionieren kann, weil die JVM durch den String Pool eine Optimierung vornimmt. Aber verlasst euch niemals darauf!

Als Best Practice gilt: Verwendet IMMER die .equals()-Methode zum Vergleich von String-Inhalten. Sie vergleicht die tatsächlichen Zeichensequenzen der Strings und ist damit die sichere und korrekte Methode für den String-Inhaltsvergleich in Java, unabhängig davon, wie die Strings erzeugt wurden.

Habt ihr noch Fragen dazu oder seid ihr auch schon mal über dieses Verhalten gestolpert? Lasst es mich wissen!