Javaschubla.de - Java als erste Programmiersprache

Der Stringpool

Wenn Strings doch Objekte sind, die man mit equals vergleichen muss und nicht mit ==, weil man sonst nur ihre Adressen vergleicht, warum gibt das folgende Programm dann "gleiche Adresse" aus?

    String s1 = "abc";
    String s2 = "abc";
    if (s1 == s2)
    {
      System.out.println("gleiche Adresse");
    }
    else
    {
      System.out.println("ungleiche Adresse");
    }

Das liegt daran, dass Java Strings recycelt. Wenn irgendwo ein String vorkommt, wird er in einem Stringpool gespeichert. Wenn er dann nochmal vorkommt, wird kein neues Stringobjekt erstellt, sondern das alte wiederverwendet. Deshalb sind s1 und s2 tatsächlich dasselbe Objekt bzw. sie verweisen auf dasselbe Objekt, die Adressen sind also gleich und s1 == s2 ergibt true.

Sogar das gibt "gleiche Adresse" aus:

    String s1 = "abc";
    String s2 = "a" + "bc";
    if (s1 == s2)
    {
      System.out.println("gleiche Adresse");
    }
    else
    {
      System.out.println("ungleiche Adresse");
    }

Bereits der Compiler erkennt, dass "a" + "bc" "abc" ergibt. Wenn man die *.class-Datei mit einem Javadecompiler (z.B. "DJ Java Decompiler") betrachtet, sieht man, dass dort auch String s2 = "abc" steht.

Die folgenden Beispiele geben hingegen "ungleiche Adresse" aus:

    String s1 = new String("abc");
    String s2 = "abc";
    if (s1 == s2)
    {
      System.out.println("gleiche Adresse");
    }
    else
    {
      System.out.println("ungleiche Adresse");
    }

Mit new wird immer ein neues Objekt erzeugt, es wird also nicht der String aus dem Pool wiederverwendet. Deshalb sollte man s1 = "abc" und nicht s1 = new String("abc") verwenden. Die Wiederverwendung von Strings aus dem Pool ist effizienter.

    String s1 = "abc";
    String a = "a";
    String bc = "bc";
    String s2 = a + bc;
    if (s1 == s2)
    {
      System.out.println("gleiche Adresse");
    }
    else
    {
      System.out.println("ungleiche Adresse");
    }

gibt auch "ungleiche Adresse" aus, denn der Compiler kann nicht mehr erkennen, dass s2 auch nur "abc" ist. Literale aneinanderhängen wie "a"+"bc" kann er, aber der Speicherplatz für Variablen wird erst zur Laufzeit, nicht schon beim Kompilieren, angelegt und mit Inhalten belegt. Der Compiler weiß also nicht, welchen Inhalt die Variablen a und bc haben, auch wenn es für uns offensichtlich ist. Deshalb wird s2 erst zur Laufzeit berechnet und ist ein neues Objekt.

    String s1 = "abc";
    String s2 = new BufferedReader(new InputStreamReader(System.in)).readLine();
    if (s1 == s2)
    {
      System.out.println("gleiche Adresse");
    }
    else
    {
      System.out.println("ungleiche Adresse");
    }

gibt "ungleiche Adresse" aus, selbst wenn der Benutzer abc eingibt. Auch dieser String wird erst zur Laufzeit erzeugt und ist deshalb nicht aus dem Pool, sondern ein neues Objekt.

Die Moral von dieser Lektion: Auch wenn der Vergleich mit == manchmal funktioniert, Strings immer mit equals vergleichen!


Übung

Spiel ein bisschen mit Strings herum. Installier dir auch einen Decompiler (unter Windows z.B. den DJ Java Decompiler) und schau dir an, was der Compiler mit den Strings wie "a"+"bc" tut.


In der nächsten Lektion geht es weiter mit Objektorientierung 3: Nicht-statische Methoden.