Objekt-Referenzen und String-Methoden
Als Basis einiger Erläuterungen verwenden wir im Weiteren eine einfache Klasse Person
:
public class Person {
private String name;
private int gebJahr;
private Person mutter;
public Person(String name, int gebJahr, Person mutter) {
this.name = name;
this.gebJahr = gebJahr;
this.mutter = mutter;
}
public String getName() {
return this.name;
}
public int getGebJahr() {
return this.gebJahr;
}
public Person getMutter() {
return this.mutter;
}
}
1. Objektreferenzen
Alle Objekte werden in Java per Referenz (wie eine URL oder Adress-Angabe) angesprochen. Die Referenz enthält immer einen definierten Wert – entweder null
oder die Adresse eines Objekts des passenden Typs.
Solche Objektreferenzen können auf verschiedene Weisen vorliegen bzw. erzeugt werden:
-
als "Ergebnis" der Objekterzeugung z.B. mit
new Person("Hansi", 1999)
-
in Form einer Objekt-Variable – deklariert z.B. mit
Person p1
(als Instanzvariable oder als lokale Variable bzw. Parameter-Variable) -
als Rückgabewert einer Methode – z.B. mit
getVater()
-
Speziell bei Strings auch z.B. mit "Hansi"
In jedem dieser Fälle kann direkt daran eine Methode dieses Objekts aufgerufen werden, sofern die Referenz nicht auf null
(= kein Objekt vorhanden) zeigt. Auf einem nicht vorhandenen Objekt können naheliegenderweise auch keine Methoden aufgerufen werden, das diese ja Zugriff auf die Instanzvariablen des jeweiligen Objekts hätten.
Genau für diesen Fall gibt es die NullPointerException
, die beim Versuch, an einer Null-Referenz eine Methode oder Instanzvariable aufzurufen, auftritt.
Sofern nicht durch vorausgehenden Code ausgeschlossen werden kann, dass die Objektreferenz null
ist, muss immer vor einem Methoden- oder Instanzvariablen-Aufruf eine null
-Prüfung erfolgen:
// ...
if (objektReferenz != null) {
objektReferenz.eineMethode()
}
// ... oder
if (name != null && name.length() > 2) { // wenn erster Teil false, kann '&&' nicht mehr true werden
// ... und der zweite Teil wird gar nicht mehr ausgeführt
}
Nun zu den oben gelisteten Objektreferenz-Möglichkeiten eine minimale Testklasse MethodenAufrufeTest
, in der diese Fälle gezeigt werden:
public class MethodenAufrufTest {
private Person mutter1 = new Person("Evi", 1991, null);
private Person kind1 = new Person("Edgar", 2011, mutter1);
public void testNeuesObjekt() {
System.out.println("Neues Objekt ... Name (Egon): "
+ new Person("Egon", 1999, null).getName());
}
public void testInstanzVariable() {
System.out.println("Objekt-Instanzvariable ... kind1-Name (Edgar): " + kind1.getName());
}
public void testLokaleVarVonNeuObj() {
Person p1 = new Person("Edi", 2002, null); // Deklaration + Zuweisung neues Objekt
System.out.println("Lokale Objektvariable ... p1-Name (Edi): " + p1.getName());
}
public void testLokaleVarVonAnderer() {
Person p1 = kind1; // Deklaration + Zuweisung bereits bestehendes Objekt
System.out.println("Lokale ObjVar-Bestehendes Obj ... p1-Name (Edgar): " + p1.getName());
}
public void testMethodenRueckgabeWert() {
System.out.println("Meth.Rückgabewert ... kind1-Mutter-Name (Evi): "
+ kind1.getMutter().getName()); // Verkettung - z.B weiter .getLength()
}
public void testLokaleVarVonMethRueckgWert() {
Person p1 = kind1.getMutter(); // Deklaration + Zuweisung Objekt per Methoden-Rückgabewert
System.out.println("Lokale ObjVar-MethRückgWert ... p1-Name (Evi): " + p1.getName());
}
public void testStringLiteral() {
System.out.println("String-Literal ..." // '\"' f. Gänsefüßchen IM Text
+ " Länge-\"Hallo\" (5): " + /*Klammer zur Verdeutlichung:*/("Hallo".length()));
}
}
2. Strings und ihre Methoden
Die Klasse String
verwenden wir "seit der ersten Stunde". Nun werden wir einiges über ihre Charakteristiken und Möglichkeiten genauer ansehen.
2.1. String-Methoden
Die String-Klasse in Java enthält eine große Anzahl von Methoden, die den Umgang mit Strings erleichtern bzw. erst sinnvoll ermöglichen.
Hier eine Auswahl einiger sehr nützlicher String-Methoden in Form jeweils eines möglichst kompakten Beispiels (die einfachste Art, String-Objektreferenzen zu erzeugen, sind String-Literale – solche werden hier verwendet):
-
int zeichenAnzahl = "Hallo".length(); // ist 5
-
boolean beginntMitHa = "Hallo".startsWith("Ha"); // ist «true»
-
boolean endetMitLo = "Hallo".endsWith("lo"); // ist «true»
-
boolean enthaeltLl = "Hallo".contains("ll"); // ist «true»
-
int posVonAl1 = "Hallo Walter".indexOf("al"); // ist 1 (erstes Auftreten)
-
int posVonAl2 = "Hallo Walter".indexOf("al", 4); // ist 7 (ab pos 4)
-
int posVonAl3 = "Hallo Walter".lastIndexOf("al"); // ist 7 (letztes Auftr.)
-
String allesGross = "Trick 17!".toUpperCase(); // ist "TRICK 17!"
-
String allesKlein = "Trick 17!".toLowerCase(); // ist "trick 17!"
-
char zeichTeAnPos4 = "grüßt :".charAt(4); // ist 't' (idx ab 0)
-
boolean leer = "".isEmpty(); // ist «true»
-
boolean frei = " \t \n ".isBlank(); // ist «true» (\t..Tab., \n..neue Z.)
-
boolean gleich = "Hallo".equals("Hallo"); // ist «true»
-
String teilInter = "Winter".substring(1); // ist "inter"
-
String teilIn = "Winter".substring(1, 3); // ist "in"
-
String txtHihi = "Hahaha".replace('a', 'i'); // ist "Hihihi"
-
String txtNene = "ha haha".replace("ha", "ne"); // ist "ne nene"
Hinweis: Diese Aufstellung lässt sich durch Copy-Paste in eine Java-Methode kopieren (die Punkte werden nicht mitkopiert).
Durch Ergänzen mit einem Print-Statement - z.B. für die letzte String-Methode:
System.out.println("\"ha haha\".replace(\"ha\", \"ne\") liefert «" + txtNene + "»");
lässt sich so einfach die Richtigkeit überprüfen (besser – mit etwas mehr Aufwand – den erwarteten Wert ebenfalls ausgeben!).
Details zu den einzelnen Methoden finden sich online – z.B. beim "Verwalter" von Java, der Fa. Oracle – unter String (Java SE 15 & JDK 15) → Method Summary.
2.2. Weitere wichtige Fakten
2.2.1. Strings sind immutable
Strings sind in Java "Immutable Objects", also unveränderbar. Das bedeutet, dass zwar sehr leicht aus einem String andere "abgeleitet" werden können, dabei entsteht aber immer ein neuer String. Demzufolge können die obigen String-Methoden den String, an dem sie aufgerufen werden, nicht verändern, sondern liefern je nach Zweck der Methode (z.B. bei "Strich".substring(3) // --> "ich"
) einen neuen String zurück (oder z.B. bei "Hallo".length()
eine Zahl).
2.2.2. Schreibweise für Sonderzeichen etc.
Da in Java das Gänsefüßchen zur syntaktischen Kennzeichnung eines String-Literal-Objekts dient, muss eine Möglichkeit gegeben werden, das Gänsefüßchen auch als "banaler Inhalt" zu verwenden. Dazu wird ein reguläres, selten benötigtes "Escape"-Zeichen (Rettungs-, Entkommens-, Ausstiegs-Zeichen) festgelegt: '\'
(Rückstrich, Backslash). Dieses dient dazu, gleich mehrere Sonderzeichen (Auswahl) zu ermöglichen:
-
'\"'
für ein normales Gänsefüßchen -
'\\'
für den Rückstrich (Backslash) selbst -
'\n'
für Zeilenschaltung -
'\t'
für Tabulator -
Das einfache Hochkomma benötigt in Strings kein
'\'
, allerdings bei Verwendung alschar
-Literal:'\''
Beispiel:
System.out.println("Erste Zeile mit \"Gänsefüßchen\" und\nzweite Zeile mit Windows-Pfad: C:\\Programme\\Eclipse");
liefert:
Erste Zeile mit "Gänsefüßchen" und zweite Zeile mit Windows-Pfad: C:\Programme\Eclipse
2.2.3. String-Vergleich
Werte Primitiver Datentypen werden in Java mit dem '=='
-Operator durchgeführt. Dieser Operator funktioniert auch bei Objekt-Datentypen, allerdings hat er hier eine andere Wirkung, da Objekte ja ausschließlich per Referenz (siehe oben) verwaltet und angesprochen werden (Details siehe Assoziationen – wichtige Fakten):
Bei Gleichheit von Referenzwerten wird auf das selbe Objekt gezeigt. Bei Strings bedeutet dies, dass die textuelle Übereinstimmung nicht ausreichend ist.
Die Sache ist kompliziert, denn Java prüft beim Anlegen eines neuen Strings in vielen, aber nicht allen Fällen, ob bereits ein gleichlautender String existiert und liefert dann die Referenz auf den bestehenden String zurück, womit der Vergleich mit '=='
wieder funktioniert.
Da man sich aber nicht darauf verlassen kann, darf man Strings NIE mit '=='
bzw. '!='
auf Gleichheit bzw. Ungleichheit überprüfen!
Stattdessen ist die String-Methode equals(…)
zu verwenden - z.B. in Form von String txt1 = "Hallo"; if (txt1.equals("Hallo")) { … }
, oder für Ungleichheit (Negation mit '!'
): if (!txt1.equals("Hallo")) { … }
.