Wir müssen uns zunächst an die Eigenschaften von drei erinnern:
1. Definition
Wenn Sie sich die API ansehen, finden Sie diese Zeichenfolge, StringBuffer und StringBuilder alle die charSequence -Schnittstelle. Obwohl sie alle mit Saiten zusammenhängen, sind ihre Verarbeitungsmechanismen unterschiedlich.
2. Verwenden Sie Szenarien
Szenarien mit String -Klasse: In Szenarien, in denen sich Zeichenfolgen nicht häufig ändern, können String -Klassen verwendet werden, wie z. B. Deklarationen von Konstanten und geringe Anzahl variabler Vorgänge.
Szenarien unter Verwendung der StringBuffer-Klasse: Wenn String-Operationen häufig (wie Spleißen, Substitution, Löschung usw.) und in einer Umgebung mit mehreren Threads ausgeführt werden, können Sie in Betracht ziehen, StringBuffer wie XML-Parsen, HTTP-Parameter-Parsen und -kapselung zu verwenden.
Szenarien unter Verwendung der StringBuilder-Klasse: Wenn String-Operationen häufig (wie Spleißen, Substitution und Löschung) und in einer einsthread-Umgebung ausgeführt werden, können Sie in Betracht ziehen, StringBuilder wie SQL-Anweisung Assembly, JSON-Kapselung usw.
III. Analyse
Um es einfach auszudrücken, ist der Hauptdifferenzunterschied zwischen String -Typ und StringBuffer -Typ tatsächlich, dass String ein unveränderliches Objekt ist. Jedes Mal, wenn Sie den String -Typ ändern, ist er tatsächlich gleichbedeutend mit der Generierung eines neuen String -Objekts und dem Anschlussen des Zeigers auf das neue String -Objekt. Daher ist es am besten, String für Zeichenfolgen zu verwenden, die den Inhalt häufig ändern, da jede Objektgenerierung einen Einfluss auf die Systemleistung hat, insbesondere wenn zu viele referenzierte Objekte im Speicher sind, wird der GC des JVM funktioniert, was definitiv sehr langsam sein wird.
Wenn Sie die StringBuffer -Klasse verwenden, ist das Ergebnis unterschiedlich. Jedes Mal, wenn das Ergebnis auf dem StringBuffer -Objekt selbst funktioniert, anstatt ein neues Objekt zu generieren und dann die Objektreferenz zu ändern. Daher empfehlen wir im Allgemeinen die Verwendung von StringBuffer, insbesondere wenn String -Objekte häufig geändert werden. In einigen besonderen Fällen wird das String -Spleißen von String -Objekten tatsächlich von der JVM als Spleißen von StringBuffer -Objekten interpretiert. Daher ist die Geschwindigkeit von String -Objekten zu diesen Zeiten nicht langsamer als StringBuffer -Objekte. Insbesondere in den folgenden String -Objektengenerierung ist die String -Effizienz viel schneller als StringBuffer:
String S1 = "Dies ist nur ein" + "einfach" + "test"; StringBuffer SB = New StringBuilder ("Dies ist nur ein"). Anhang ("einfach"). Append ("Test");Sie werden überrascht sein, dass die Geschwindigkeit der Erzeugung von String S1 -Objekten einfach zu schnell ist, und zu diesem Zeitpunkt hat StringBuffer keinen Vorteil in der Geschwindigkeit. Tatsächlich ist dies ein Trick des JVM. In den Augen des JVM, das
String S1 = "Dies ist nur ein" + "einfach" + "Test";
Eigentlich:
String S1 = "Dies ist nur ein einfacher Test";
Natürlich braucht es nicht viel Zeit. Aber was Sie hier beachten sollten, ist, dass die Geschwindigkeit beispielsweise nicht so schnell ist, wenn Ihre Zeichenfolge aus einem anderen String -Objekt stammt:
String S2 = "Dies ist nur ein"; String S3 = "Simple"; String S4 = "Test"; String S1 = S2 + S3 + S4;
Zu diesem Zeitpunkt wird das JVM dies auf die ursprüngliche Weise regelmäßig tun.
4. Eingehende Optimierung und Verarbeitung von JVM
Gibt es wirklich die oben genannten Leistungskosten? String -Spleißen ist so häufig. Gibt es keine spezielle Verarbeitungsoptimierung? Die Antwort ist, dass diese Optimierung beim Kompilieren von Java zu Bytecode in JVM durchgeführt wird.
Wenn ein Java -Programm ausgeführt werden möchte, dauert es zwei Zeiträume, kompilieren Sie Zeit und Laufzeit. Zum Kompilierzeit wandelt der Java JVM (Compiler) die Java -Datei in Bytecode um. Zur Laufzeit führt die Java Virtual Machine (JVM) die mit Kompilierung erzeugte Bytecode aus. In diesen beiden Perioden hat Java die sogenannte Zusammenstellung erreicht und überall läuft.
Lassen Sie uns mit den Optimierungen experimentieren, die während der Kompilierungsperiode vorgenommen wurden, und wir erstellen einen Code, der Leistungskosten haben kann.
Public Class Conatenation {public static void main (String [] args) {String username = "andy"; String Age = "24"; String Job = "Entwickler"; String Info = Benutzername + Alter + Job; System.out.println (info); }}Compile concattenation.java. Holen Sie sich cazenation.class
javac concatten.java
Anschließend verwenden wir Javap, um die kompilierte Verkettungsklasse -Datei zu dekompilieren. Javap -c -Verkettung. Wenn der Befehl javap nicht gefunden wird, sollten Sie das Verzeichnis hinzufügen, in dem sich die Javap der Umgebungsvariablen befindet oder den vollständigen Pfad von Javap verwendet.
17: 22: 04 -Androidyue ~/Workspace_ADT/STRINGS/SRC $ JAVAP -C -CONCATENATION COND COMPILED aus "concattenation.java" öffentliche Klassenverhütung {öffentliche Verkettung (); Code: 0: ALOAD_0 1: Invokespecial #1 // Methode Java/Lang/Object. Code: 0: LDC #2 // String Andy 2: Store_1 3: LDC #3 // String 24 5: Store_2 6: LDC #4 // Stringentwickler 8: Store_3 9: Neu #5 // Klasse Java/Lang/StringBuilder 12: dup 13: Invokespecial #6 // Method Java/Lang/String/Stringbuilder. invokeVirtual #7 // Methode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/stringBuilder; 20: ALOAD_2 21: InvokeVirtual #7 // Methode Java/Lang/StringBuilder.Append: (ljava/lang/String;) ljava/lang/StringBuilder; 24: ALOAD_3 25: InvokeVirtual #7 // Methode Java/Lang/StringBuilder.Append: (ljava/lang/String;) ljava/lang/stringBuilder; 28: InvokeVirtual #8 // Methode Java/Lang/StringBuilder.toString :() Ljava/Lang/String; 31: Store 4 33: Getstatic #9 // Feld Java/Lang/System.out: ljava/io/printstream; 36: ALOAD 4 38: InvokeVirtual #10 // Methode Java/io/printstream.println: (ljava/lang/string;) v 41: return}Unter ihnen sind LDC, Speicher usw. Java -Bytecode -Anweisungen, ähnlich wie Anweisungen für die Montage. Die folgenden Kommentare verwenden Java-bezogene Inhalte zur Erläuterung. Wir können sehen, dass es viele StringBuilders gibt, aber wir nennen sie im Java -Code ohne Anzeige. Dies ist die Optimierung von Javajvm. Wenn Javajvm auf String -Spleißen trifft, wird ein StringBuilder -Objekt erstellt. Das Spleißen dahinter besteht darin, die Anhangsmethode des StringBuilder -Objekts zu rufen. Auf diese Weise werden wir keine Probleme geben, über die wir uns Sorgen machen.
5. allein auf die JVM -Optimierung verlassen?
Seit der JVM uns geholfen hat, die Optimierung zu optimieren, reicht es aus, sich ausschließlich auf die JVM -Optimierung zu verlassen? Natürlich nicht.
Schauen wir uns einen Code an, der für niedrige Leistung nicht optimiert wurde
public void implicitusSestringBuilder (String [] Werte) {String result = ""; für (int i = 0; i <values.length; i ++) {result += values [i]; } System.out.println (Ergebnis);}Mit Javac zusammenstellen und mit Javap aussehen
public void implicitusSestringBuilder (Java.lang.String []); Code: 0: ldc #11 // String 2: store_2 3: iconst_0 4: istore_3 5: iload_3 6: aload_1 7: arraylength 8: if_icmpge 38 11: new #5 // class java/lang/StringBuilder 14: dup 15: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 18: ALOAD_2 19: InvokeVirtual #7 // Methode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/stringBuilder; 22: ALOAD_1 23: ILOAD_3 24: AALOAD 25: InvokeVirtual #7 // Methode Java/Lang/StringBuilder.Append: (ljava/lang/String;) ljava/lang/stringBuilder; 28: InvokeVirtual #8 // Methode Java/Lang/StringBuilder.toString :() Ljava/Lang/String; 31: store_2 32: iinc 3, 1 35: goto 5 38: getstatic #9 // Feld java/lang/system.out: ljava/io/printstream; 41: ALOAD_2 42: InvokeVirtual #10 // Methode Java/IO/Printstream.println: (ljava/lang/string;) v 45: Rückkehr
Unter ihnen 8: if_icmpge 38 und 35: Goto 5 bilden eine Schleife. 8: IF_ICMPGE 38 bedeutet, dass, wenn der Ganzzahlvergleich des JVM -Operand -Stapels größer oder gleich ist (i <das entgegengesetzte Ergebnis der Werte), in Zeile 38 (System.OUT) springt. 35: Goto 5 bedeutet, direkt in Zeile 5 zu springen.
Aber hier gibt es eine sehr wichtige Sache, dass die Erstellung von StringBuilder -Objekten zwischen Schleifen auftritt, was bedeutet, dass die Schleifen, wie oft die Loops mehrere StringBuilder -Objekte erzeugen, offensichtlich nicht gut ist. Nackter Code mit niedrigem Niveau.
Optimieren Sie es leicht, um die Qualität sofort zu verbessern.
public void explicitusStringBuilder (String [] Werte) {StringBuilder result = new StringBuilder (); für (int i = 0; i <values.length; i ++) {result.append (Werte [i]); }}Entsprechende kompilierte Informationen
11: ALOAD_1 12: ArrayLength 13: if_icmpge 30 16: ALOAD_2 17: ALOAD_1 18: ILOAD_3 19: AALOAD 20: InvokeVirtual #7 // Methode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/stringbuilder; 23: Pop 24: iinc 3, 1 27: Goto 10 30: Rückkehr
Wie aus oben ersichtlich ist, bilden Sie 13: IF_ICMPGE 30 und 27: GOTO 10 eine Schleifenschleife, während 0: Neu #5 außerhalb der Schleife liegt, so dass StringBuilder nicht mehrmals erstellt wird.
Im Allgemeinen müssen wir versuchen, eine implizite oder explizite Erstellung von Stringbuildern im Schleifenkörper zu vermeiden. Daher haben diejenigen, die verstehen, wie der Code zusammengestellt wird und wie er intern ausgeführt wird, relativ hohe Code -Ebenen.
6. Schlussfolgerung
In den meisten Fällen StringBuffer> String
Java.lang.StringBuffer ist eine thread-sichere Sequenz von Variablenzeichen. Ein String-ähnlicher String-Puffer, kann aber nicht geändert werden. Obwohl es zu jedem Zeitpunkt eine bestimmte Reihenfolge von Zeichen enthält, können die Länge und der Inhalt der Sequenz durch einige Methodenaufrufe geändert werden. String -Puffer können in Programmen für Multithreading sicher verwendet werden. Und diese Methoden können bei Bedarf synchronisiert werden, sodass alle Vorgänge in einer bestimmten Instanz in einer seriellen Reihenfolge auftreten, die mit der Reihenfolge der Methodenaufrufe übereinstimmt, die von jedem beteiligten Thread erstellt wurden.
Die Hauptvorgänge auf StringBuffer sind die Anhang- und Einfügungsmethoden, die überladen werden können, um alle Datenart zu akzeptieren. Jede Methode kann die angegebenen Daten effektiv in eine Zeichenfolge umwandeln und dann die Zeichen dieser Zeichenfolge in den String -Puffer anhängen oder einfügen. Die Anhangsmethode fügt diese Zeichen immer zum Ende des Puffers hinzu. Die Methode Einfügen fügt Zeichen am angegebenen Punkt hinzu.
Wenn sich Z auf ein String -Puffer -Objekt bezieht, dessen aktueller Inhalt "Start" ist, ruft diese Methode Z.Append ("LE") den String -Puffer auf "erschreckend" (akkumuliert). und Z.Insert (4, "LE") ändert den Streicherpuffer, um "Starlet" zu enthalten.
In den meisten Fällen StringBuilder> StringBuffer
Java.lang.StringBuilder Eine variable Zeichensequenz ist neu in Java 5.0. Diese Klasse bietet eine StringBuffer-kompatible API, ist jedoch nicht garantiert synchronisiert, sodass das Nutzungsszenario ein einzelnes Thread ist. Diese Klasse ist als einfacher Ersatz für StringBuffer ausgelegt, wenn String -Puffer von einem einzelnen Thread verwendet werden (dies ist üblich). Wenn möglich, wird empfohlen, diese Klasse zuerst einzunehmen, da sie in den meisten Implementierungen schneller als StringBuffer ist. Die Nutzungsmethoden von beiden sind im Grunde genommen gleich.