Wir haben bisher fast ausschließlich mit den Datentypen int, double oder boolean gearbeitet. Wir wissen jedoch auch, dass zum Ausgeben von Texten oder Ergebnissen Strings verwendet werden. In diesem Abschnitt soll näher auf Datentypen für die Arbeit mit Zeichen(-ketten) eingegangen werden.
Datentyp char
Der Datentyp char speichert genau ein einzelnes Zeichen. Dabei wird jedoch intern gar kein (Text-)Zeichen gespeichert sondern ein Zahlwert von 0 bis 65535. Dieser wird durch die Deklarierung als char dann jedoch als Zeichen des UTF-16-Zeichensatzes interpretiert.
Um zu wissen, welches Zeichen sich hinter welcher Zahl verbirgt, hilft uns z. B. die ASCII-Tabelle, die jedem Wert von 0 bis 255 ein Zeichen zuordnet:
Diese Codetabelle ist jedoch schon lange nicht mehr ausreichend, da dort nur die grundlegenden Zeichen enthalten sind. Einen Überblick über alle möglichen Zeichen des UTF-16-Zeichensatzes kann man hier einsehen: https://www.fileformat.info/info/charset/UTF-16/list.htm
Ein Zeichen vom Datentyp char wird in einfache Hochkomma gesetzt. Durch Casting mit (int) bzw. (char) können die einzelnen Werte in char-Zeichen bzw. char-Zeichen in die entsprechenden Werte umgewandelt werden.
public static void main(String[] args) {
System.out.println('A');
System.out.println(+'A'); // Umwandlung char -> int
System.out.println((int) 'A'); // Umwandlung char -> int
System.out.println((char) 70); // Umwandlung int -> char
}
Die Ausgabe würde hier so aussehen (65 ist der ASCII-Zahlwert des Zeichens ‚A‘):
A
65
65
F
Wichtig ist, klar zwischen einem Wert und einem Zeichen zu unterteilen:
public static void main(String[] args) {
System.out.println('1'); // Ausgabe: 1
System.out.println((int) '1'); // Ausgabe: 49 (ASCII-Wert des Zeichens 1)
}
Da char-Zeichen intern als Zahlen verarbeitet werden, kann man damit auch rechnen:
public static void main(String[] args) {
System.out.println( 'A' + 10 ); // Ausgabe: 75
System.out.println( 'A' + 'C' ); // Ausgabe: 132
System.out.println( "A" + "A" ); // Ausgabe: AA
System.out.println( 2 * 'A' ); // Ausgabe: 130
}
Datentyp String
Der Datentyp String ist im Gegensatz zu den Datentypen int, double oder char kein einfacher Datentyp, sondern eine Klasse. Strings können u. a. als Feld von char-Zeichen aufgefasst werden. Für die Abfrage der einzelnen Werte an gewünschten Stellen des String können wir jedoch nicht den Feldoperator [] verwenden, sondern greifen auf die Funktion charAt(int index) der Klasse String zurück, welche das Zeichen an der Stelle index liefert:
public static void main(String[] args) {
String s = "Dies ist ein Beispieltext.";
char c = s.charAt(0);
System.out.println(c + " " + s.charAt(2)); // Ausgabe: "D e"
}
Da man so auf jedes einzelne Zeichen eines Strings zugreifen kann, sind verschiedene Aufgaben lösbar, wie z. B. das Zählen von gewünschten Buchstaben, das Ersetzen von Buchstaben oder auch das Manipulieren bzw. Entfremden von Texten.
Strings sind Klassen, wir arbeiten mit String-Objekten
Wie oben schon erwähnt, sind Strings Objekte, die von einer Klasse String abgeleitet werden. Über Objekte und Klassen informieren wir uns an anderer Stelle, jedoch müssen wir uns auf einige Besonderheiten einstellen.
Vergleich von Strings
Variablen konnten wir bisher sehr gut mit einander vergleichen, bei Strings ist dies etwas anders:
public static void main(String[] args) {
String person1 = new String ("Toni Stark");
String person2 = new String ("Toni Stark");
if (person1 == person2) {
System.out.println("Die Personen sind gleich!");
} else {
System.out.println("Die Personen sind verschieden!");
}
}
Dieser Vergleich erzeugt die Ausgabe Die Personen sind verschieden!. Woran liegt das?
Die beiden String-Objekte haben zwar den gleichen Wert, sind aber selbst nicht gleich. Für person1 und person2 wird jeweils ein Speicherplatz reserviert, in dem der Wert gespeichert wird. Die Namen person1 und person2 dienen jeweils als Zeiger auf den Speicherplatz, in dem das String-Objekt gespeichert wird. Wir möchten eigentlich den Wert vergleichen, testen oben jedoch, ob die Objekte die gleichen sind (genauer, ob die Zeiger auf den gleichen Platz im Speicher zeigen). Zum Vergleich der Werte müssen wir daher wieder auf eine Methode der String-Klasse zurückgreifen (equals). Die korrekte Bedingung müsste also so lauten:
public static void main(String[] args) {
String person1 = new String ("Toni Stark");
String person2 = new String ("Toni Stark");
if (person1.equals(person2)) {
System.out.println("Die Personen sind gleich!");
} else {
System.out.println("Die Personen sind verschieden!");
}
}
Kleine Gemeinheit für Anfänger
In den oberen Beispielen haben wir die Strings mit new erzeugt – das haben wir jedoch bisher nie gebraucht, weshalb also hier im Beispiel? Probieren wir es ohne das new:
public static void main(String[] args) {
String person1 = "Toni Stark";
String person2 = "Toni Stark";
if (person1.equals(person2)) {
System.out.println("Die Personen sind gleich!");
} else {
System.out.println("Die Personen sind verschieden!");
}
}
Hier bekommen wir (obwohl wir von verschiedenen Objekten ausgehen) die Ausgabe Die Personen sind gleich!. Das widerspricht offensichtlich unseren Überlegungen …
Die Lösung liefert der Literal Pool, ein in der Klasse String angelegter Speicher, in dem zur Laufzeit je ein Exemplar bereits erzeugter, lexikalisch identischer Strings vorgehalten wird, um Speicher und Performance zu sparen. Er ist zunächst leer. Wird ein String neu erzeugt, so wird zunächst in diesem Pool nachgesehen, ob ein identischer String dort bereits eingetragen ist. Ist dies der Fall, wird lediglich eine Referenz auf den dort registrierten erzeugt (und KEIN eigenes Objekt), ansonsten wird er dem Pool neu hinzugefügt. Im Beispiel zeigen somit person1 und person2 auf dasselbe Objekt, von dem im Literal Pool eine Referenz gespeichert ist.
Werden jedoch, wie beiden beiden Variablen person1 und person2 String-Objekte mit new erzeugt, so geschieht dies unabhängig vom Pool. Beide Objekte sind somit eigenständige Instanzen mit individuellen Speicherorten, deren Vergleich mit dem Vergleichsoperator false ergeben muss. Man erkennt hier, dass, wenn möglich, neue Strings somit ohne Verwendung des new-Operators erzeugt werden sollten.
Strings und Zuweisungen
Ein weiteres Problem gibt es bei Zuweisungen von Strings. Die Codezeilen …
public static void main(String[] args) {
String person1 = "Toni Stark";
String person2 = "Iron Man";
System.out.println(person1 + " " + person2);
person1 = person2;
System.out.println(person1 + " " + person2);
}
… führen zu der Ausgabe …
Toni Stark Iron Man
Iron Man Iron Man
Was ist passiert? Mit der Anweisung person1 = person2 wird (der Zeiger auf) das Objekt person1 durch (den Zeiger auf) das Objekt person2 überschrieben. Beide verweisen nun auf den gleichen Speicherplatz, nämlich auf den von person2. Noch wichtiger … die Werte von person1 sind verloren.
Zum Kopieren des Inhaltes eines Strings in einen anderen verwenden wir daher die Methode valueOf (es gibt aber auch andere Möglichkeiten):
person1 = String.valueOf(person2);
Wichtige Methoden der Klasse String
Da Strings Objekte der Klasse String sind, verfügen alle Strings über eine Vielzahl von Methoden, von denen die wichtigsten im Folgenden vorgestellt werden sollen.
length()
… gibt die Länge eines Strings an.
String text = "Informatik ist toll";
int l = text.length(); // l = 19
charAt(int index)
… liefert das Zeichen als Charakter an der Stelle index.
String text = "Informatik ist toll";
char c = text.charAt(5); // c = 'm'
substring(int i, int j)
… kopiert aus einem String einen Teilstring heraus. i bezeichnet den Index des ersten Zeichens, j-1 des Index des letzten Zeichens.
String text = "Informatik ist toll";
String s1 = text.substring(3,7); // s1 = "orma"
equals(String s)
… vergleicht den Inhalt zweier Strings.
String text1 = "Informatik ist toll";
String text2 = "Informatik ist TOLL";
boolean gleich = text1.equals(text2); // gleich = false
toUpperCase() / toLowerCase()
… wandelt alle Zeichen des Strings in Großbuchstaben / Kleinbuchstaben um.
String text1 = "Informatik ist toll";
text1 = text1.toUpperCase(); // text1 = "INFORMATIK IST TOLL"
compareTo(String s)
… stellt eine alphabetische Reihenfolge in Bezug auf s fest.
String n1 = "Anton";
String n2 = "Berta";
i = n1.compareTo(n2); // i = -1 (n1 vor n2)
i = n2.compareTo(n1); // i = 1 (n2 nach n1)
i = n1.compareTo(n1); // i = 0 (n1 gleich mit n1)
compareTo() gibt es auch in der Variante compareToIgnoreCase(), bei der die Groß- und Kleinschreibung ignoriert wird.
indexOf(String s) / indexOf(String s, int index) /lastindexOf(String s)
Die Methode indexOf sucht das erste Vorkommen der Zeichenkette s innerhalb des String-Objekts. Wird s gefunden, liefert die Methode den Index des ersten übereinstimmenden Zeichens zurück, andernfalls wird -1 zurückgegeben. Die Methode gibt es auch in einer Version, die einen Parameter vom Typ char akzeptiert. In diesem Fall sucht sie nach dem ersten Auftreten des angegebenen Zeichens.
Die zweite Variante von indexOf arbeitet wie die erste, beginnt mit der Suche aber erst ab Position fromIndex. Wird s beginnend ab dieser Position gefunden, liefert die Methode den Index des ersten übereinstimmenden Zeichens, andernfalls -1. Auch diese Methode gibt es in einer Variante, die anstelle eines String-Parameters ein Argument des Typs char erwartet. Ihr Verhalten ist analog zur vorherigen.
Die Methode lastIndexOf sucht nach dem letzten Vorkommen des Teilstrings s im aktuellen String-Objekt. Wird s gefunden, liefert die Methode den Index des ersten übereinstimmenden Zeichens, andernfalls -1. Wie die beiden vorherigen Methoden gibt es auch lastIndexOf wahlweise mit einem Parameter vom Typ char und mit einem zweiten Parameter, der die Startposition der Suche bestimmt.
String text = "Informatik ist toll";
int i1 = text.indexOf("ist"); // i1 = 11
int i2 = text.indexOf('o',10); // i2 = 16
int i3 = text.lastIndexOf("t"); // i3 = 15
replace(char oldchar, char newchar)
Mit Hilfe von replace wird eine zeichenweise Konvertierung des aktuellen String-Objekts durchgeführt. Dabei wird jedes Auftreten des Zeichens oldchar durch das Zeichen newchar ersetzt.
String text = "Informatik ist toll";
text = text.replace('o','@'); // text = "Inf@rmatik ist t@ll"