Heim  >  Artikel  >  Java  >  Analyse des Java StringBuilder- und StringBuffer-Quellcodes

Analyse des Java StringBuilder- und StringBuffer-Quellcodes

高洛峰
高洛峰Original
2017-01-22 11:28:401190Durchsuche

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&#39;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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn