Advanced Java Services | String, StringBuffer, StringBuilder |
Bevor wir weiter in die Objektorientierung einsteigen verschaffen wir uns erst eine kleine Übersicht über wichtige Standardklassen, deren Konstruktoren und Methoden. Wir beginnen mit dem Dreigespann String, StringBuilder und Stringbuffer.
Wichtige Konstruktoren | |
---|---|
String() | Initializes a newly created String object so that it represents an empty character sequence. |
String(char[] value) | Allocates a new String so that it represents the sequence of characters currently contained in the character array argument. |
String(String original) | Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. |
String(StringBuffer buffer) | Allocates a new string that contains the sequence of characters currently contained in the StringBuffer argument. |
String(StringBuilder builder) | Allocates a new string that contains the sequence of characters currently contained in the StringBuilder argument. |
Wichtige Methoden | |
---|---|
Returntyp | Name der Methode |
char | charAt(int index) Returns the character at the specified index. |
int | compareTo(String anotherString) Compares two strings lexicographically. |
boolean | contains(CharSequence s)
Returns true if and only if this string contains the specified sequence of char values. |
boolean | contentEquals(StringBuffer sb) Returns true if and only if this String represents the same sequence of characters as the specified StringBuffer. |
boolean | contentEquals(CharSequence sequence) Returns true if and only if this String represents the same sequence of characters as the specified CharSequence. |
boolean | endsWith(String suffix) Tests if this string ends with the specified suffix. |
boolean | equals(Object anObject) Compares this string to the specified object. |
int | indexOf(int ch) Returns the index within this string of the first occurrence of the specified character. |
int | indexOf(int ch, int fromIndex) Returns the index within this string of the first occurrence of the specified character, starting the search at the specified index. |
int | length() Returns the length of this string. |
String | replace(char oldChar, char newChar)
Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar. |
String | substring(int beginIndex, int endIndex)
Returns a new string that is a substring of this string. |
char[] | toCharArray() Converts this string to a new character array. |
String | toLowerCase() Converts all of the characters in this String to lower case using the rules of the default locale. |
String | toUpperCase() Converts all of the characters in this String to upper case using the rules of the default locale. |
Der wichtigste Satz über Strings: String objects are immutable
Ohne Verwendung eines Konstruktors
String s1 = "kalimera" ; String s2 = "kalimera" ;
Achtung, hier zeigen beide Referenzen auf ein und denselben Speicherbereich !
Konstruktor erhält ein char-Array
String s3 = new String( new char[]{ 'k', 'a', 'l', 'i', 'm', 'e', 'r', 'a' } ) ;
Konstruktor erhält eine StringBufferReferenz
StringBuffer sb = new StringBuffer(); sb.append(69); String s3 = new String(sb) ; // Der String enthält die Ziffern 6 und 9 als ASCII-Zeichen
Konstruktor erhält einen String
String s4 = new String(s1) ;
Dies ist ein Kopierkonstruktor, es wird also ein neuer Speicherbereich angelegt, s1 und s4 zeigen auf verschiedene Speicherbereiche.
Vorsicht
Man darf sich durch die Namen von einigen Methoden nicht täuschen lassen. Dazu einige Beispiele
String st = "HALLO"; st.toLowerCase();
Hier wird keineswegs der String st in Kleinbuchstaben umgewandelt. Es wird ein neuer String angelegt, der "HALLO" in kleinen Buchstaben enthält. Der String st bleibt unverändert. Da der Returnwert der Methode nicht zugewiesen wird, ist der neue String sofort ein Fall für den GarbageCollector.
String st = "HALLO"; String klein = st.toLowerCase();
Diesmal klappt es. Der String klein enthält jetzt die Zeichenfolge "hallo", st bleibt unverändert. Auch die replace-Methode läßt (wie alle Methoden !) den String unverändert.
String st = "abrakadabra"; st.replace('a', 'e');
Hier wird also wieder ein neuer String erzeugt, der vom Müllschlucker entsorgt wird, weil es keine Referenz auf ihn gibt. Also wieder zuweisen:
String s1 = "abrakadabra"; String s2 = s1.replace('a', 'e');
Jetzt steht in s2 "ebrekedebre" und in s1 immer noch "abrakadabra" .
Adressen vergleichen mit dem Operator ==
Generell muß man unterscheiden zwischen dem Vergleich von Referenzen und dem Vergleich von Objekten.
Zwei unterschiedliche Referenzen r1 und r2 können auf das gleiche Objekt zeigen und das heißt, daß die
beiden Referenzen ein und dieselbe Adresse beinhalten. In diesem Fall ergibt der Vergleich r1 == r2
natürlich true. Zu zwei verschiedenen Objekten gibt es immer mindestens zwei Referenzen mit verschiedenen
Adressen. Dann ergibt der Zeigervergleich r1 == r2 den Wert false.
String s1 = "hallo"; String s2 = "hallo"; String s3 = "Hallo"; System.out.println("s1 == s2 ergibt " + (s1==s2) ); // true System.out.println("s1 == s3 ergibt " + (s1==s3) ); // false s3 = new String(s1) ; System.out.println("s1 == s3 ergibt " + (s1==s3) ); // false
Im obigen Beispiel ist s2 kein neuer String. Da bereits ein String "hallo" existiert, erzeugt der
Compiler keinen weiteren solchen String. s3 dagegen zeigt auf ein neues Objekt, da sein Inhalt nicht
identisch zu "hallo" ist. Der Konstruktor String( String s) ist ein Kopierkonstruktor und legt immer
ein neues Objekt an. Die Referenz s3 zeigt nun also auf ein Duplikat von s1, der alte Inhalt "Hallo"
geht verloren. Inhaltlich sind jedoch s1 und s3 offensichtlich gleich.
Inhalte vergleichen mit der Methode equals()
String s1 = "hallo"; String s2 = "hallo"; String s3 = new String(s1);
nach dem vorigen wiisen wir, daß s1 und s3 auf verschiedene Objekte zeigen. Trotzdem können die Inhalte der beiden Objekte "gleich" sein. Wir finden es vernünftig, zu sagen, daß s3 und s1 gleiche Strings sind, weil beide Objekte die gleiche Zeichenfolge darstellen. Genau diesen Vergleich macht die Methode equals(). Diese Methode wird von der Klasse Object geerbt. Die Originalmethode aus Object macht jedoch auch nur einen Zeigervergleich, wie ein Blick in den Quellcode zeigt:
public boolean equals(Object obj) { return (this == obj); }
In der Klasse String wurde jedoch die Methode so überschrieben, daß sie auf Gleichheit der Zeichenfolgen prüft. Für Neugierige hier der Quellcode der Überschreibung von equals() in String.
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; // The count is the number of characters in the String. if (n == anotherString.count) { char v1[] = value; // value ist das interne char-Array, in dem die Zeichen gespeichert werden char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; // The offset is the first index of the storage that is used. while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
Die obigen Zeilen bedeuten kurz gesagt: Wenn das übergebene Objekt vom Typ String ist, die Strings gleiche Länge und gleichen Inhalt haben, dann werden sie als gleich angesehen. Noch ein Beispiel:
String s1 = "hallo"; String s2 = new String(s1) ; String s3 = "Hallo"; System.out.println("s1 == s2 ergibt " + (s1==s2) ); // false System.out.println("s1.equals(s2) ergibt " + s1.equals(s2) ); // true System.out.println("s1.equals(s3) ergibt " + s1.equals(s3) ); // false
Hier ist s2 ein neuer String mit altem Inhalt. Der Zeigervergleich liefert also false,
der Vergleich mit equals() true.
Inhalte vergleichen mit der Methode compareTo()
Die Klasse String verfügt über mehrere Vergleichsmethoden. Zusätzlich zur Methode equals() gibt es noch
die Vergleichsmethoden compareTo() und contentEquals(). Mit compareTo() kann man zusätzlich zur
Gleichheit auch lexikographisch vergleichen. In diesem Sinne ist etwa "Benno" kleiner als "Brigitte",
da 'e' vor 'r' kommt, genau wie im Telefonbuch. Allerdings ist "benno" größer als "Brigitte",
es ist nämlich 'b' > 'B', da das kleine Alphabet im ASCII-Code hinter dem großen liegt.
Mit den Methoden contentEquals() ist es schließlich möglich einen String mit Objekten vom Typ
CharSequence zu vergleichen. Wenn wir in der Objektorientierung die Themen Vererbung und Interfaces
besprochen haben werden wir noch einmal darauf zurückkommen.
String s1 = "Benno"; String s2 = "Brigitte"; String s3 = "benno"; String s4 = new String(s1); System.out.println("s1.compareTo(s2) = " + s1.compareTo(s2) ); // < 0 System.out.println("s3.compareTo(s2) = " + s3.compareTo(s2) ); // > 0 System.out.println("s1.compareTo(s4) = " + s1.compareTo(s4) ); // = 0
Man kann Strings nicht mit < oder > vergleichen, genau deswegen gibt es ja die Methode compareTo(). Die folgende Tabelle zeigt, wie man < bzw. > ersetzen muß.
s1 < s2 <=> s1.compareTo(s2) < 0 s1 == s2 <=> s1.compareTo(s2) == 0 s1 > s2 <=> s1.compareTo(s2) > 0
Angenehmerweise ist der Operator + für Strings überladen.
String st = "ein string" ; Xxx var = ... ;
In dieser Situation kann man st und var "addieren", die Reihenfolge ist dabei egal, es entsteht immer ein String. Die Variable var wird automatisch in einen String verwandelt.
String so = st + var ; String oder_so = var + st ;
Bleibt die Frage, für welche Datentypen Xxx stehen kann ? Wenn wir wissen, wie der Compiler das Plus intern übersetzt, dann können wir diese Frage beantworten. Der Compiler übersetzt so:
String so = new StringBuffer().append(st).append(var).toString(); String oder_so = new StringBuffer().append(var).append(st).toString();
Also müssen wir in der API nachschlagen, für welche Parameter die Methode append() überladen ist.
Das Ergebnis:
append ist überladen für
boolean, char, char[], double, float, int, long, Object, String und StringBuffer.
Überlegen sie sich, daß damit Xxx jeder beliebige Datentyp sein kann, z.Bsp. auch short oder byte
oder Color oder jedes beliebige Array.
Dies wird oft verwendet, um irgendwelche Daten schnell in Strings zu verwandeln, was besonders für die
graphische Oberfläche wichtig ist, da hier Strings die einzigen Objekte sind, die ausgegeben werden
können. Für graphische Komponenten, die Text darstellen können, gibt es etwa die Methode
setText(String text), die ausschließlich Stringparameter versteht. Hier arbeitet man gerne mit
einem Leerstring, wie das folgende Beispiel zeigt.
int i = 5; double d = 7.5 ; StringBuffer sb = ... ; button.setText( "" + i ) ; button.setText( "" + d ) ; button.setText( "" + sb ) ;
In der Version 1.5 wird die Klasse StringBuilder eingeführt. Sie ersetzt weitgehend die Klasse StringBuffer.
Beide Klassen enthalten die gleichen Methoden und Konstruktoren. Der wichtige Unterschied: StringBuffer ist
threadsicher, StringBuilder ist es nicht.
In der API heißt es zu StringBuffer:
A thread-safe, mutable sequence of characters. A string buffer is like a String, but can be modified.
At any point in time it contains some particular sequence of characters, but the length and content of
the sequence can be changed through certain method calls.
Dagegen liest man über StringBuilder:
A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no
guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer
in places where the string buffer was being used by a single thread (as is generally the case). Where
possible, it is recommended that this class be used in preference to StringBuffer as it will be faster
under most implementations.
Wichtige Konstruktoren | |
---|---|
StringBuilder() |
Constructs a string buffer with no characters in it and an initial capacity of 16 characters. |
StringBuilder(String str) |
Constructs a string buffer so that it represents the same sequence of characters as the string argument; in other words, the initial contents of the string buffer is a copy of the argument string. |
StringBuilder(CharSequence seq) |
Constructs a string buffer that contains the same characters as the specified CharSequence. |
Wichtige Methoden | |
---|---|
Returntyp | Name der Methode |
StringBuilder |
append(boolean b) Appends the string representation of the boolean argument to the string buffer. This method is overloaded for the following argument types: byte, int, long, float, double, char[], String, StringBuilder, Object. Returns a reference to this StringBuilder object. |
char |
charAt(int index) The specified character of the sequence currently represented by the string buffer, as indicated by the index argument, is returned. |
StringBuilder |
deleteCharAt(int index) Removes the character at the specified position in this StringBuilder (shortening the StringBuilder by one character). Returns a reference to this StringBuilder object. |
int |
indexOf(String str) Returns the index within this string of the first occurrence of the specified substring. |
StringBuilder |
insert(int offset, boolean b) Inserts the string representation of the boolean argument into this string buffer. The second argument is overloaded for the following argument types: char, int, long, float, double, char[], String, Object. Returns a reference to this StringBuilder object. |
int |
length() Returns the length (character count) of this string buffer. |
StringBuilder |
reverse() The character sequence contained in this string buffer is replaced by the reverse of the sequence. Returns a reference to this StringBuilder object. |
String |
substring(int start, int end) Returns a new String that contains a subsequence of characters currently contained in this StringBuilder. |
String |
toString() Converts to a new string representing the data in this string buffer. Subsequent changes to the string buffer do not affect the contents of the String. |
Der wichtigste Satz über StringBuilder:
StringBuilders support mutable strings
Ein weiterer wichtiger Unterschied:
StringBuilder besitzt keine Vergleichsmethode compareTo()
Wichtige Konstruktoren | |
---|---|
StringBuffer() |
Constructs a string buffer with no characters in it and an initial capacity of 16 characters. |
StringBuffer(String str) |
Constructs a string buffer so that it represents the same sequence of characters as the string argument; in other words, the initial contents of the string buffer is a copy of the argument string. |
StringBuffer(CharSequence seq) |
Constructs a string buffer that contains the same characters as the specified CharSequence. |
Wichtige Methoden | |
---|---|
Returntyp | Name der Methode |
StringBuffer |
append(boolean b) Appends the string representation of the boolean argument to the string buffer. This method is overloaded for the following argument types: byte, int, long, float, double, char[], String, StringBuffer, Object. Returns a reference to this StringBuffer object. |
char |
charAt(int index) The specified character of the sequence currently represented by the string buffer, as indicated by the index argument, is returned. |
StringBuffer |
deleteCharAt(int index) Removes the character at the specified position in this StringBuffer (shortening the StringBuffer by one character). Returns a reference to this StringBuffer object. |
int |
indexOf(String str) Returns the index within this string of the first occurrence of the specified substring. |
StringBuffer |
insert(int offset, boolean b) Inserts the string representation of the boolean argument into this string buffer. The second argument is overloaded for the following argument types: char, int, long, float, double, char[], String, Object. Returns a reference to this StringBuffer object. |
int |
length() Returns the length (character count) of this string buffer. |
StringBuffer |
reverse() The character sequence contained in this string buffer is replaced by the reverse of the sequence. Returns a reference to this StringBuffer object. |
String |
substring(int start, int end) Returns a new String that contains a subsequence of characters currently contained in this StringBuffer. |
String |
toString() Converts to a new string representing the data in this string buffer. Subsequent changes to the string buffer do not affect the contents of the String. |
Der wichtigste Satz über StringBuffer:
StringBuffers support mutable strings
Ein weiterer wichtiger Unterschied:
StringBuilder besitzt keine Vergleichsmethode compareTo()
Ein char-Array in einen String verwandeln :
char[] arr = { 'a' , 'g' , 'a', 'p' , 'i' } ; String st = new String(arr) ;
Einen String in ein char-Array verwandeln :
String st = "agapi" ; char[] arr = st.toCharArray();
Einen String in einen StringBuffer/StringBuilder verwandeln :
String st = "agapi" ; StringBuilder sb = new StringBuilder(st) ;
Einen StringBuffer in einen String verwandeln :
StringBuffer sb = new StringBuffer("aga") ; sb.append("pi"); String st = new String(sb) ; // oder String st2 = sb.toString() ;
Einen StringBuilder in einen String verwandeln :
StringBuilder sb = new StringBuilder("aga") ; sb.append("pi"); String st = new String(sb) ; // oder String st2 = sb.toString() ;
String mit Stringbuffer vergleichen
Bis zur Version 1.3 des JDK mußte man einen StringBuffer in einen String umwandeln
und dann vergleichen.
String st = "Max"; StringBuffer sb = new StringBuffer(); sb.append( new char[] { 'M', 'a', 'x'} ); boolean boo = st.equals( sb.toString() ) ; // true int erg = st.compareTo( sb.toString() ) ; // 0
Ab der Version 1.4 gibt es in String die neue Methode contentEquals(). Sie arbeitet wie equals(), erhält aber ein StringBufferobjekt als Parameter.
String st = "Max"; StringBuffer sb = new StringBuffer(); sb.append( new char[] { 'm', 'a', 'x'} ); boolean boo = st.contentEquals(sb) ; // false
Die Variante mit toString() legt für den Vergleich extra einen neuen String an, der nach dem
vergleich vom GarbageCollector entsorgt werden muß, contentEquals() dagegen vergleicht direkt
die beiden Zeichenpuffer.
String mit Stringbuilder vergleichen
Ab der Version 1.5 des JDK gibt es in der Klasse String eine zusätzliche Methode contentEquals() die
ein CharSequenceobjekt als Parameter bekommt. Da StringBuilder das Interface CharSequence implementiert
kann man diese Methode für den Vergleich verwenden.
String st = "Max"; StringBuilder sb = new StringBuilder(); sb.append( new char[] { 'm', 'a', 'x'} ); boolean boo = st.contentEquals(sb) ; // false
StringBuffer mit Stringbuffer/StringBuilder vergleichen
Entweder beide StringBuffers in Strings verwandeln und dann mit equals() oder compareTo
oder nur einen StringBuffer/StringBuilder umwandeln und dann mit contentEquals().
Übung zu String und StringBuffer/StringBuilder
Palindrome