StringBuilder und StringBuffer sind zwei häufig verwendete Klassen zum Betreiben von Strings. Wie wir alle wissen, ist StringBuilder threadsicher, während StringBuffer threadsicher ist. Ersteres wurde in JDK1.5 hinzugefügt und letzteres war in JDK1.0 verfügbar. Lassen Sie uns ihre interne Umsetzung analysieren.
1. Vererbungsbeziehung
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
Wie Sie sehen können, ist die Vererbungsbeziehung der beiden Klassen genau gleich. Serialisierbar ist ein Flag, das serialisiert werden kann. Die CharSequence-Schnittstelle umfasst die Methoden charAt(), length(), subSequence() und toString(). Die String-Klasse implementiert diese Schnittstelle ebenfalls. Der Fokus liegt hier auf der abstrakten Klasse AbstractStringBuilder, die die Implementierung der meisten Operationen von StringBuilder und StringBuffer kapselt.
2. AbstractStringBuilder
1. Variablen und Konstruktionsmethoden
char[] value; int count; AbstractStringBuilder() { } AbstractStringBuilder(int capacity) { value = new char[capacity]; }
AbstractStringBuilder verwendet intern ein char[]-Array, um Zeichenfolgen zu speichern Geben Sie die Anfangskapazitätsmethode während des Baus an.
2. Kapazitätserweiterung
public void ensureCapacity(int minimumCapacity) { if (minimumCapacity > 0) ensureCapacityInternal(minimumCapacity); } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); } void expandCapacity(int minimumCapacity) { int newCapacity = value.length * 2 + 2; if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); }
Die Erweiterungsmethode wird letztendlich durch expandCapacity() implementiert. Bei dieser Methode wird die Kapazität zunächst auf das ursprüngliche Kapazitätsplus erweitert 2: Wenn die Kapazität zu diesem Zeitpunkt immer noch unter der angegebenen Kapazität liegt, setzen Sie die neue Kapazität auf „MinimumCapacity“. Stellen Sie dann fest, ob ein Überlauf vorliegt. Setzen Sie die Kapazität auf Integer.MAX_VALUE. Abschließend wird der Wert kopiert, was natürlich ein zeitaufwändiger Vorgang ist.
3. append()-Methode
public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; }
append() ist die am häufigsten verwendete Methode und weist viele Formen der Überladung auf. Das Obige ist eines davon und wird zum Anhängen von Zeichenfolgen verwendet. Wenn str null ist, wird die Methode appendNull() aufgerufen. Diese Methode hängt tatsächlich die Zeichen „n“, „u“, „l“ und „l“ an. Wenn es nicht null ist, wird zuerst die Kapazität erweitert und dann die getChars()-Methode von String aufgerufen, um str an das Ende des Werts anzuhängen. Schließlich wird das Objekt selbst zurückgegeben, sodass append() kontinuierlich aufgerufen werden kann.
3. StringBuilder
AbstractStringBuilder hat die meisten erforderlichen Methoden bereits implementiert. StringBuilder und StringBuffer müssen nur noch aufgerufen werden. Werfen wir einen Blick auf die Implementierung von StringBuilder.
1. Konstruktor
public StringBuilder() { super(16); } public StringBuilder(int capacity) { super(capacity); } public StringBuilder(String str) { super(str.length() + 16); append(str); } public StringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq); }
Es ist ersichtlich, dass die Standardkapazität von StringBuilder 16 beträgt. Natürlich können Sie auch die Anfangskapazität angeben oder dem StringBuilder-Objekt mit einer vorhandenen Zeichenfolge einen Anfangswert zuweisen.
2. append()-Methode
public StringBuilder append(String str) { super.append(str); return this; } public StringBuilder append(CharSequence s) { super.append(s); return this; }
Es gibt viele überladene Methoden für append(), hier sind nur zwei. Offensichtlich ist hier die Methode in der übergeordneten Klasse AbstractStringBuilder, die direkt aufgerufen wird.
3. toString()
public String toString() { // Create a copy, don't share the array return new String(value, 0, count); }
Die toString()-Methode gibt ein neues String-Objekt zurück, das keinen Speicher mit dem Originalobjekt teilt. Tatsächlich gilt das Gleiche auch für die subString()-Methode in AbstractStringBuilder.
4. SringBuffer
StiringBuffer ähnelt StringBuilder, außer dass viele Methoden lSynchronized-Änderungen verwenden, wie zum Beispiel die folgende Methode:
public synchronized int length() { return count; } public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } public synchronized void setLength(int newLength) { toStringCache = null; super.setLength(newLength); }
Wie Sie sehen können, wird Synchronized tatsächlich vor der Methode hinzugefügt.
Darüber hinaus gibt es in den oben genannten Methoden append() und setLength() eine Variable toStringCache. Diese Variable wird für den Cache der neuesten toString()-Methode verwendet. Dieser Variable wird der Wert Null zugewiesen, wenn der StringBuffer geändert wird. Der toString von StringBuffer lautet wie folgt:
public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
Wenn toStringCache bei dieser Methode null ist, wird es zuerst zwischengespeichert. Das endgültig zurückgegebene String-Objekt ist etwas anders. Dieser Konstruktor hat auch einen Parameter true. Suchen Sie den Quellcode von String und werfen Sie einen Blick darauf:
String(char[] value, boolean share) { // assert share : "unshared not supported"; this.value = value; }
Es stellt sich heraus, dass das mit dieser Konstruktionsmethode erstellte String-Objekt den String nicht wirklich kopiert, sondern nur auf den Wert zeigt auf den Konstruktionsparameter, um Geld zu sparen. Dieser Konstruktor verfügt jedoch über Paketzugriffsrechte und kann unter normalen Umständen nicht aufgerufen werden.
Zusammenfassung
StringBuilder und StringBuffer sind beide veränderbare Zeichenfolgen. Ersteres ist threadsicher und letzteres ist threadsicher.
Die meisten Methoden von StringBuilder und StringBuffer rufen die Implementierung der übergeordneten Klasse AbstractStringBuilder auf. Sein Erweiterungsmechanismus ändert zunächst die Kapazität auf das Zweifache der ursprünglichen Kapazität plus 2. Die maximale Kapazität ist Integer.MAX_VALUE, also 0x7ffffffff.
Die Standardkapazität von StringBuilder und StringBuffer beträgt 16. Es ist am besten, die Größe der Zeichenfolge im Voraus abzuschätzen, um den durch die Erweiterung verursachten Zeitaufwand zu vermeiden.
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er Ihnen dabei hilft, zwei häufig verwendete Klassen zum Betreiben von Strings in Java kennenzulernen: StringBuilder und StringBuffer.
Weitere Artikel zur Quellcodeanalyse von Java StringBuilder und StringBuffer finden Sie auf der chinesischen PHP-Website!