W3docs

Java String-Klasse

Ein tieferer Einblick in Javas String-Klasse — Design, interne Struktur und die wichtigsten Methoden.

String ist der mit Abstand meistgenutzte Referenztyp in Java. Man begegnet ihm von Anfang an — String name = "Ada"; — und er schleicht sich ohne viel Aufhebens in den eigenen Code. Dieser Teil des Buches geht tiefer. Die Klasse hat mehr zu bieten, als ihre Oberfläche vermuten lässt: ein festgelegtes internes Layout, eine besondere Syntaxbehandlung, die andere Typen nicht erhalten, einen Memory-Pool, der die Identität beeinflusst, und eine bewusste Designentscheidung (Unveränderlichkeit), die sich durch Threading, Hashing und Sicherheit zieht.

Dieses Kapitel ist die Karte. Der Rest von Teil 9 füllt die einzelnen Regionen aus.

Was für ein Ding ist ein String?

Ein String ist ein gewöhnliches Java-Objekt — java.lang.String, im selben Paket wie Object und Integer. Es ist final, man kann es also nicht ableiten, und jede Methode, die einen String scheinbar „verändert", gibt tatsächlich einen neuen zurück. Das Original wird nie angetastet.

String greeting = "hello";
greeting.toUpperCase();          // returns "HELLO" — discarded
System.out.println(greeting);    // still prints "hello"
greeting = greeting.toUpperCase();
System.out.println(greeting);    // now prints "HELLO"

Diese Gewohnheit, einen neuen Wert zurückzugeben, ist die wichtigste Eigenschaft der Klasse. Sie wird ausführlich in Java String-Unveränderlichkeit behandelt.

Besondere Sprachunterstützung

Zwei Syntaxelemente sind für String reserviert und lassen sich nicht auf andere Typen ausdehnen:

  • String-Literale"hello" erzeugt direkt ein String-Objekt, ohne new. Der Compiler dedupliziert außerdem identische Literale in den String-Pool.
  • Der +-Operator — für Strings überladen: "a" + "b" ergibt "ab". Sogar gemischte Ausdrücke wie "score: " + 42 funktionieren, weil Java die rechte Seite in einen String konvertiert.

Im Hintergrund übersetzen moderne Java-Compiler +-Ketten mithilfe von StringBuilder oder dem invokedynamic-basierten StringConcatFactory, sodass man die Verkettung selten manuell schreiben muss. Der Compiler weiß, was zu tun ist.

Interne Struktur

Vor Java 9 enthielt jeder String ein char[] — zwei Bytes pro Zeichen, unabhängig vom Inhalt. Java 9 führte Compact Strings ein: Das Backing-Array ist nun ein byte[], ergänzt um ein Ein-Byte-Feld coder, das angibt, ob die Bytes Latin-1 (ein Byte pro Zeichen) oder UTF-16 (zwei Bytes) kodiert sind. Für Text, der in Latin-1 passt — der Großteil von Code, Konfigurationen, Bezeichnern und normalem englischen Text — halbiert das in etwa den Speicherbedarf, ohne die API zu verändern.

Das Feld ist nicht sichtbar, nicht veränderbar und muss nicht beachtet werden. Aber es ist der Grund, warum stringlastige Programme unter JDK 9+ spürbar weniger Heap verbrauchen als unter JDK 8.

Die wichtigsten Methodenfamilien

Die String-API ist umfangreich, lässt sich aber in einige überschaubare Gruppen einteilen:

Inspektion. length(), isEmpty(), isBlank(), charAt(i), codePointAt(i), hashCode().

Suche. indexOf, lastIndexOf, contains, startsWith, endsWith, matches.

Extraktion. substring(start), substring(start, end), chars(), codePoints(), toCharArray().

Transformation. toUpperCase(), toLowerCase(), trim(), strip(), replace, replaceAll, replaceFirst, concat.

Aufteilen und Verbinden. split, String.join — behandelt in split() und join().

Formatierung. String.format, die Instanzmethode formatted und printf-ähnliche Ausgabe — behandelt in String-Formatierung.

Vergleich. equals, equalsIgnoreCase, compareTo, compareToIgnoreCase, contentEquals — behandelt in String-Vergleich.

Konvertierung. valueOf (statisch), toString (Instanz), Parse-Hilfsmethoden auf Integer, Double usw. — behandelt in String-Konvertierungen.

Vollständige API-Listings finden sich in der JDK-Javadoc. Die Kunst liegt darin, zu erkennen, welche Familie man braucht — nicht darin, jede Überladung auswendig zu kennen.

Strings sind Sequenzen von UTF-16-Code-Einheiten

charAt(i) und length() zählen UTF-16-Code-Einheiten, keine Unicode-Zeichen. Für Text innerhalb der Basic Multilingual Plane (der Großteil gängiger Schriften) entspricht ein char einem Zeichen, und der Unterschied spielt keine Rolle. Für ergänzende Zeichen — die meisten Emoji, einige CJK-Erweiterungen, alte Schriften — nimmt ein einzelnes sichtbares Zeichen zwei chars ein, ein sogenanntes Surrogate-Paar.

String emoji = "🙂";
System.out.println(emoji.length());          // 2 — two code units
System.out.println(emoji.codePointCount(0, emoji.length())); // 1 — one code point

Wer nach Unicode-Code-Points iterieren möchte, nutzt codePoints() oder codePointAt. Für die meisten ASCII-nahen Anwendungsfälle — CSV-Parsing, Log-Zeilen formatieren, Bezeichner vergleichen — sind length() und charAt genau das Richtige.

Veränderliche Verwandte: StringBuilder und StringBuffer

Wenn man einen String Stück für Stück aufbauen muss, erzeugt wiederholtes += bei jedem Schritt einen neuen String. Die Standardbibliothek bietet dafür zwei veränderliche Begleiter:

  • StringBuilder — schnell, single-threaded.
  • StringBuffer — dieselbe API, synchronisierte Methoden, sinnvoll nur wenn mehr als ein Thread in denselben Buffer schreibt.

Beide haben parallele APIs und parallele Kapitel in diesem Teil des Buches.

Ein ausgearbeitetes Beispiel

Eine kleine Übung, die die häufigsten Familien berührt — Inspektion, Suche, Extraktion, Transformation und Konvertierung — auf derselben Eingabe. Die Ausgabe Zeile für Zeile lesen; jeder Aufruf illustriert ein Werkzeug aus der obigen Liste.

java— editable, runs on the server

Die letzte Zeile ist der Knalleffekt. Nach all den Transformationen ist line selbst byteidentisch mit dem Literal, mit dem man angefangen hat — der Beweis, dass das Modell „gibt einen neuen zurück" real ist und kein bloßer Dokumentationshinweis.

Was kommt als Nächstes

Strings haben ein Speichermodell, das in der Standardbibliothek einmalig ist: identische Literale teilen sich den Speicher, und man kann beliebige Strings mit einem einzigen Methodenaufruf in diesen gemeinsamen Pool aufnehmen. Weiter zu Java String-Pool.

Übungen

Übung
Welche Aussage über Javas `String`-Klasse ist wahr?
Welche Aussage über Javas `String`-Klasse ist wahr?
Was this page helpful?