Überblick
StringBuilder und StringBuffer sind zwei leicht verwirrende Konzepte. Dieser Artikel beginnt mit dem Quellcode und untersucht einfach die Ähnlichkeiten und Unterschiede zwischen den beiden.
Es ist leicht zu wissen, dass einer dieser beiden Thread-Safe ist und der fadensichere ineffizient ist.
Beschreibung in Java Doc
Java Doc ist eine Annotation, die von Personen geschrieben wurde, die Quellcode schreiben. Schauen wir uns zuerst Java Doc an.
StringBuilder
Eine veränderliche Sequenz von Zeichen. Diese Klasse bietet eine API, die mit StringBuffer kompatibel ist, jedoch ohne Garantie für die Synchronisation. Diese Klasse ist für die Verwendung als Drop-In-Ersatz für StringBuffer an Stellen ausgelegt, an denen der Streicherpuffer von einem einzelnen Thread verwendet wurde (wie es im Allgemeinen der Fall ist). Wenn möglich, wird empfohlen, diese Klasse für StringBuffer bevorzugt zu werden, da sie unter den meisten Implementierungen schneller ist.
Die Hauptvorgänge eines StringBuilders sind die Anhang- und Einfügungsmethoden, die überladen werden, um Daten jeglicher Art zu akzeptieren. Jedes konvertiert effektiv ein bestimmtes Datum in eine Zeichenfolge und findet die Zeichen dieser Zeichenfolge in den String Builder an oder fügt sie dann an. Die Anhangsmethode fügt diese Zeichen immer am Ende des Erbauers hinzu. Die Einfügenmethode fügt die Zeichen an einem bestimmten Punkt hinzu.
Wenn sich Z auf ein String Builder -Objekt bezieht, dessen aktuelle Inhalte "Start" sind, würde die Methode aufrufen Z.Append ("Le") dazu führen, dass der String -Builder "erschrecken" enthält, während Z.insert (4, "LE") den String -Builder verändern würde, um "Starrett" zu enthalten.
Wenn sich SB im Allgemeinen auf eine Instanz eines StringBuilder bezieht, hat SB.Append (x) den gleichen Effekt wie Sb.insert (Sb.Length (), x).
Jeder String Builder hat eine Kapazität. Solange die Länge der im String Builder enthaltenen Zeichensequenz die Kapazität nicht überschreitet, ist es nicht erforderlich, einen neuen internen Puffer zuzuweisen. Wenn der interne Puffer überläuft, wird er automatisch größer.
Instanzen von StringBuilder sind nicht sicher für mehrere Threads. Wenn eine solche Synchronisation erforderlich ist, wird empfohlen, dass Java.lang.StringBuffer verwendet wird.
Sofern nicht anders angegeben, führt das Übergeben eines Null -Arguments an einen Konstruktor oder eine Methode in dieser Klasse zu einer Nullpointerexception.
Seit:
1.5
Autor:
Michael McCloskey
Siehe auch:
Java.lang.StringBuffer
Java.lang.String
StringBuffer
Eine thread-safe, veränderliche Sequenz von Zeichen. Ein String -Puffer ist wie eine Zeichenfolge, kann aber geändert werden. Zu jedem Zeitpunkt enthält es eine bestimmte Sequenz von Zeichen, aber die Länge und der Inhalt der Sequenz können durch bestimmte Methodenaufrufe geändert werden.
String -Puffer sind für mehrere Threads sicher. Die Methoden werden gegebenenfalls so synchronisiert, dass sich alle Operationen in einer bestimmten Instanz so verhalten, als ob sie in einer seriellen Reihenfolge auftreten, die mit der Reihenfolge der Methodenaufrufe übereinstimmt, die von jedem der einzelnen beteiligten Themen erstellt wurden.
Die Hauptvorgänge auf einem StringBuffer sind die Anhang- und Einfügungsmethoden, die überladen werden, um Daten jeglicher Art zu akzeptieren. Jeder konvertiert effektiv ein bestimmtes Datum in eine Zeichenfolge und findet die Zeichen dieser Zeichenfolge in den String -Puffer an oder fügt sie dann an. Die Anhangsmethode fügt diese Zeichen immer am Ende des Puffers hinzu. Die Einfügenmethode fügt die Zeichen an einem bestimmten Punkt hinzu.
Wenn sich Z auf ein String -Puffer -Objekt bezieht, dessen aktuelle Inhalte "Start" sind, würde die Methode aufrufen Z.Append ("Le") dazu führen, dass der String -Puffer "erschrecken" enthält, während Z.Insert (4, "LE") den String -Puffer verändern würde, um "Starrett" zu enthalten.
Wenn sich SB im Allgemeinen auf eine Instanz eines StringBuffer bezieht, hat SB.Append (x) den gleichen Effekt wie Sb.insert (Sb.Length (),
Immer wenn ein Betrieb auftritt, der eine Quellsequenz betrifft (z. B. Anhang oder Einfügen aus einer Quellsequenz), synchronisiert diese Klasse nur auf dem String -Puffer, der den Vorgang ausführt, nicht auf der Quelle. Beachten Sie, dass StringBuffer zwar so konzipiert ist, dass sie gleichzeitig von mehreren Threads verwendet werden können, wenn der Konstruktor oder der Anhang oder der Einfügen eine Quellsequenz übergeben werden, die über Threads geteilt wird, muss der aufrufende Code sicherstellen, dass der Vorgang eine konsistente und unveränderliche Ansicht der Quellsequenz für die Dauer des Betriebs hat. Dies könnte durch den Anrufer erfüllt werden, der während des Aufrufs des Vorgangs eine Schloss hält, indem sie eine unveränderliche Quellsequenz verwendet oder die Quellsequenz nicht über Threads weitergegeben wird.
Jeder Stringpuffer hat eine Kapazität. Solange die Länge der im Stringpuffer enthaltenen Zeichensequenz die Kapazität nicht überschreitet, ist es nicht erforderlich, ein neues internes Pufferarray zuzuweisen. Wenn der interne Puffer überläuft, wird er automatisch größer.
Sofern nicht anders angegeben, führt das Übergeben eines Null -Arguments an einen Konstruktor oder eine Methode in dieser Klasse zu einer Nullpointerexception.
Nach der Veröffentlichung JDK 5 wurde diese Klasse mit einer äquivalenten Klasse ergänzt, die für einen einzelnen Thread, StringBuilder, entwickelt wurde. Die StringBuilder -Klasse sollte im Allgemeinen für diesen vorliegen, da sie alle gleichen Operationen unterstützt, aber schneller ist, da sie keine Synchronisation durchführt.
Seit:
JDK1.0
Autor:
Arthur Van Hoff
Siehe auch:
Java.lang.StringBuilder
Java.lang.String
Javadoc -Zusammenfassung
Aus dem obigen können wir sehen:
Sowohl StringBuffer als auch StringBuilder können als variable Zeichenfolgen angesehen werden.
StringBuffer ist Thread-Safe und erscheint zuerst und ist in JDK1.0 erhältlich.
StringBuilder ist nicht-thread-safe und erscheint später und existiert nur in JDK1.5.
Die Schnittstellen der beiden sind genau gleich, und StringBuilder ist schneller.
Tatsächlich ist es gut, es normalerweise zu verwenden, nur diese Punkte zu kennen, aber ich möchte immer noch sehen, wie es im Quellcode implementiert wird.
Quellcode
Wie man Fadensicherheit erreicht
Sie können aus dem Quellcode sehen, dass beide einen abstrakten AbstractStringBuilder -Klassenklassen erben
Public Final Class StringBuffer erweitert abstraktStringBuilder implementiert java.io.serializable, CharsequencePublic Final Class StringBuilder erweitert AbstractStringBuilder implementiert java.io.ioSerializable, Charsequence, Charsequence, Charsequence
Die Codemenge ist nicht sehr groß, StringBuilder440 -Codezeilen, StringBuffer718 -Codezeilen und das Beste ist abstrakteStringbuilder mit insgesamt 1440 Codezeilen.
Aus mehreren Perspektiven betrachten wir den Code, eines ist das, was einige wichtige interne Strukturen aussehen, und der andere ist, wie die von uns üblicherweise verwendeten Funktionen implementiert werden. Da String unveränderlich ist, wird sie in einem konstanten Pool platziert. Es ist vermutet, dass StringBuilder und StringBuffer mit einem Zeichenarray implementiert werden sollten.
/*** Der Wert wird für den Zeichenspeicher verwendet. */ char [] Wert; /*** Die Anzahl ist die Anzahl der verwendeten Zeichen. */ int count;
Es ist ersichtlich, dass die Daten mit Wert gespeichert und die Länge durch eine Anzahl dargestellt wird.
Sehen wir uns die verschiedenen Implementierungen mehrerer gängiger Methoden an.
StringBuffer
@Override public synchronisierte StringBuffer append (String str) {toStringCache = null; Super.Append (str); gib dies zurück; } / ** * @throws stringIndexoutOfBoundSexception {@inheritdoc} * / @Override public Synchronized StringBuffer Insert (int offset, string str) {toStringCache = null; super.insert (offset, str); gib dies zurück; } @Override public Synchronisierte String -String toString () {if (toStringCache == null) {toStringCache = arrays.copyofrange (Wert, 0, count); } return New String (toStringCache, true); }StringBuilder
@Override public StringBuilder append (string str) {Super.Append (str); gib dies zurück; } / ** * @throws stringIndexoutOfBoundSexception {@inheritdoc} * / @Override public StringBuilder Insert (int offset, string str) {super.insert (offset, str); gib dies zurück; } @Override public String toString () {// Erstellen Sie eine Kopie, teilen Sie das Array -Return New String (Wert, 0, count) nicht. }Wie aus dem Code ersichtlich ist, fügt Strinbbuffer in den meisten Fällen nur ein synchronisiertes Schlüsselwort hinzu, um die Sicherheit der Thread zu gewährleisten. Aber die ToString -Methode ist anders, also werde ich später darüber sprechen.
Initialisieren Sie die Größe und wie man wächst
Da es sich tatsächlich um ein Array handelt, ist die Größen- und Wachstumsmethode des Ausgangs des Arrays sehr wichtig. Schauen wir uns den Code durch.
/** * Konstruiert einen String -Puffer ohne Zeichen und eine * Anfangskapazität von 16 Zeichen. */ public StringBuffer () {Super (16); } /** * konstruiert einen String -Builder ohne Zeichen und eine * Anfangskapazität von 16 Zeichen. */ public StringBuilder () {Super (16); }Wie Sie sehen können, zeigen diese beiden Standardkonstruktoren an, dass die Standardarray -Größe 16 beträgt.
Warum 16? Ich habe nicht verstanden.
Was ist als nur Sorgen darüber, wie man wächst? Schauen wir uns die Implementierung von Anhängen an
public AbstractStringBuilder append (string str) {if (str == null) return appendnull (); int len = str.length (); sealEcapacityInternal (count + len); Str.Getchars (0, Len, Wert, Graf); zählen += len; gib dies zurück; } /** * Diese Methode hat den gleichen Vertrag wie die Sicherungssuarität, wird aber niemals synchronisiert. */ private void sealecapacityInternal (int minimumCapacity) {// Überlauf -unbewusster Code, wenn (minimumCapacity - value.length> 0) ExpanceCapacity (minimumCapacity); } /** * Dies implementiert die Expansionsemantik der Gewinnung ohne * Größenüberprüfung oder -Synchronisation. */ void ExpandCapacity (int minimumCapacity) {int newcapacity = value.length * 2 + 2; if (newCapacity - minimumCapacity <0) newCapacity = minimumCapacity; if (newCapacity <0) {if (minimumCapacity <0) // Überlauf -Neue outofMemoryError (); newCapacity = Integer.max_Value; } value = arrays.copyof (value, newCapacity); }Die obigen drei Methoden erklären, wie die Kapazität erweitert werden kann.
Setzen Sie die aktuelle Kapazität *2+2 ein
Wenn die neu zugegebene Länge größer als dieser Wert ist, setzen Sie sich auf den neu zollen Wert fest
Wenn Überlauf, throutofMemoryError
Implementierung des ToString in StringBuffer
/*** Ein Cache des letzten Wertes, der durch das ToString zurückgegeben wurde. Löschen * Wenn der StringBuffer geändert wird. */ privat transient char [] toStringCache; @Override public synchronisierte StringBuffer append (String str) {toStringCache = null; Super.Append (str); gib dies zurück; } @Override public Synchronisierte String -String toString () {if (toStringCache == null) {toStringCache = arrays.copyofrange (Wert, 0, count); } return New String (toStringCache, true); }Wie Sie sehen können, wird ein Array -ToSstringCache definiert. Jedes Mal, wenn sich die Daten ändert, wird dies auf Null gesetzt. Nehmen Sie es beim ToString erneut aus den aktuellen Daten.
Das vorübergehende Schlüsselwort soll verhindern, dass dieses Array serialisiert wird.
Zusammenfassung
Tatsächlich ist der Quellcode von Java selbst relativ einfach. Wenn Sie mit dem Quellcode beginnen können, können Sie viele Prinzipien tiefer verstehen. Dieser Artikel listet einfach einige Quellcodes auf und erklärt kurz die Ähnlichkeiten und Unterschiede zwischen StringBuffer und StringBuilder. Interessierte Freunde können es sich selbst ansehen.
Der obige Artikel befasst sich kurz mit den Ähnlichkeiten und Unterschieden zwischen StringBuilder und StringBuffer aus der Sicht des Quellcode (umfassende Analyse) ist der gesamte Inhalt, den ich mit Ihnen teile. Ich hoffe, es kann Ihnen eine Referenz geben und ich hoffe, Sie können Wulin.com mehr unterstützen.