Ich glaube, dass jeder den Unterschied zwischen String und StringBuffer gut versteht, aber es wird geschätzt, dass es immer noch viele Kollegen gibt, denen die Arbeitsprinzipien dieser beiden Klassen nicht klar sind. Heute werde ich dieses Konzept für alle überprüfen In J2SE 5.0 wurde eine neue Zeichenoperationsklasse eingeführt: StringBuilder. Was sind also die Unterschiede zwischen diesem StringBuilder und StringBuffer und der String-Klasse, die wir zum ersten Mal kennengelernt haben? Welches sollten wir in verschiedenen Situationen verwenden? Ich möchte meine Ansichten zu diesen Kategorien mitteilen und hoffe auch, dass jeder seine Meinung äußern kann. Jeder hat Fehler gemacht und es ist eine gute Gelegenheit, etwas zu lernen.
Kurz gesagt besteht der Hauptleistungsunterschied zwischen dem String-Typ und dem StringBuffer-Typ tatsächlich darin, dass String ein unveränderliches Objekt ist (Warum? Fragen Sie die Designer von Java, warum String kein nativer Typ ist?). Daher wird der String-Typ jedes Mal geändert Tatsächlich entspricht dies dem Generieren eines neuen String-Objekts und dem anschließenden Zeigen des Zeigers auf das neue String-Objekt. Daher ist es am besten, String nicht für Zeichenfolgen zu verwenden, deren Inhalt sich häufig ändert. Denn jedes Mal, wenn ein Objekt generiert wird, wirkt es sich auf die Systemleistung aus. Insbesondere wenn sich zu viele nicht referenzierte Objekte im Speicher befinden, beginnt der GC der JVM zu arbeiten und die Geschwindigkeit wird definitiv ziemlich langsam sein. Hier ist ein Beispiel, das nicht sehr passend ist:
Wenn dies der Fall ist, befinden sich nach Abschluss der for-Schleife und wenn die Objekte im Speicher nicht vom GC gelöscht wurden, mehr als 20.000 im Speicher, eine erstaunliche Zahl, und wenn dies ein System ist, das von vielen verwendet wird Leute, dann ist die Zahl nicht sehr groß, daher muss jeder bei der Verwendung vorsichtig sein.
Wenn Sie die StringBuffer-Klasse verwenden, sind die Ergebnisse jedes Mal unterschiedlich. Das Ergebnis ist eine Operation am StringBuffer-Objekt selbst, anstatt ein neues Objekt zu generieren und dann die Objektreferenz zu ändern. Daher empfehlen wir im Allgemeinen die Verwendung von StringBuffer, insbesondere wenn sich String-Objekte häufig ändern. In einigen Sonderfällen wird die String-Verkettung von String-Objekten von der JVM tatsächlich als die Verkettung von StringBuffer-Objekten interpretiert, sodass in diesen Fällen die Geschwindigkeit von String-Objekten nicht langsamer ist als die von StringBuffer-Objekten, insbesondere die folgenden String-Objekte Unter diesen ist die String-Effizienz viel schneller als die von StringBuffer:
Sie werden überrascht sein, dass die Geschwindigkeit beim Generieren von String S1-Objekten einfach zu hoch ist und StringBuffer derzeit überhaupt keinen Geschwindigkeitsvorteil hat. Tatsächlich ist dies ein Trick der JVM. In den Augen der JVM
Daraus erhalten wir die erste Schlussfolgerung: In den meisten Fällen StringBuffer > String
Und wie schneidet StringBuilder im Vergleich dazu ab? Lassen Sie mich es zunächst kurz vorstellen. StringBuilder ist eine neu hinzugefügte Klasse in JDK5.0. Der Unterschied zwischen ihr und StringBuffer ist wie folgt (Quelle: JavaWorld):
Java.lang.StringBuffer Threadsichere veränderbare Zeichenfolge. Ein String-Puffer ähnlich wie String, der jedoch nicht geändert werden kann. String-Puffer können sicher von mehreren Threads verwendet werden. Diese Methoden können bei Bedarf synchronisiert werden, sodass alle Vorgänge auf einer bestimmten Instanz scheinbar in einer seriellen Reihenfolge ausgeführt werden, die mit der Reihenfolge der Methodenaufrufe jedes beteiligten Threads übereinstimmt.
Jeder String-Puffer hat eine bestimmte Kapazität. Solange die Länge der im Zeichenfolgenpuffer enthaltenen Zeichenfolge diese Kapazität nicht überschreitet, besteht keine Notwendigkeit, ein neues internes Pufferarray zuzuweisen. Diese Kapazität wird automatisch erhöht, wenn der interne Puffer überläuft. Ab JDK 5.0 wurde dieser Klasse eine äquivalente Klasse für die Verwendung in einem einzelnen Thread, StringBuilder, hinzugefügt. Im Allgemeinen sollte die StringBuilder-Klasse dieser Klasse vorgezogen werden, da sie dieselben Vorgänge unterstützt, aber schneller ist, da sie keine Synchronisierung durchführt.
Es ist jedoch unsicher, eine Instanz von StringBuilder mit mehreren Threads zu verwenden. Wenn eine solche Synchronisierung erforderlich ist, wird die Verwendung von StringBuffer empfohlen.
Nachdem dies gesagt ist, denke ich, dass jeder den Unterschied zwischen ihnen verstehen kann, also lassen Sie uns unten eine allgemeine Ableitung vornehmen:
In den meisten Fällen StringBuilder > StringBuffer
Daher gilt nach dem Transitivsatz dieser Ungleichung: In den meisten Fällen StringBuilder > StringBuffer > String
Nachdem wir nun solche Ableitungsergebnisse haben, führen wir einen Test durch, um Folgendes zu überprüfen:
Der Testcode lautet wie folgt:
/** Erstellt eine neue Instanz von testssb */
final static int ttime = 10000;//Anzahl der Testschleifen
öffentliche Testssb() {
}
public void test(String s){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s += "add";
}
long over = System.currentTimeMillis();
System.out.println("Die von der Operation "+s.getClass().getName()+" verwendete Zeit beträgt: " + (over - begin) + " Millisekunden" );
}
public void test(StringBuffer s){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("add");
}
long over = System.currentTimeMillis();
System.out.println("Die von der Operation "+s.getClass().getName()+" verwendete Zeit beträgt: " + (over - begin) + " Millisekunden" );
}
public void test(StringBuilder s){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("add");
}
long over = System.currentTimeMillis();
System.out.println("Die von der Operation "+s.getClass().getName()+" verwendete Zeit beträgt: " + (over - begin) + " Millisekunden" );
}
// String-Verkettung direkt auf String testen
public void test2(){
String s2 = "abadf";
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
Zeichenfolge s = s2 + s2 + s2 ;
}
long over = System.currentTimeMillis();
System.out.println("Die Zeit, die zum Ausführen des String-Objektreferenzadditionstyps benötigt wird, beträgt: " + (over - begin) + " Millisekunden" );
}
public void test3(){
long begin = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
String s = „abadf“ + „abadf“ + „abadf“ ;
}
long over = System.currentTimeMillis();
System.out.println("Die zum Hinzufügen von Operationszeichenfolgen benötigte Zeit beträgt: "+ (über - beginnen) + " Millisekunden" );
}
public static void main(String[] args){
String s1="abc";
StringBuffer sb1 = new StringBuffer("abc");
StringBuilder sb2 = new StringBuilder("abc");
testssb t = new testssb();
t.test(s1);
t.test(sb1);
t.test(sb2);
t.test2();
t.test3();
}
}
Es scheint, dass Sie den Unterschied zwischen StringBuffer und StringBuilder immer noch nicht erkennen können. Fügen Sie ttime zu 30000 hinzu und sehen Sie:
Die für die Ausführung des Typs java.lang.String benötigte Zeit beträgt: 53444 Millisekunden Die für die Ausführung des Typs java.lang.StringBuffer verwendete Zeit beträgt: 15 Millisekunden Die für die Ausführung des Typs java.lang.StringBuilder verwendete Zeit beträgt: 15 Millisekunden Die Zeit Wird verwendet, um den Additionstyp „String-Objektreferenz“ zu betreiben. Dauer: 31 Millisekunden. Das Hinzufügen von Strings dauerte: 0 Millisekunden
Es gibt immer noch keinen großen Leistungsunterschied zwischen StringBuffer und StringBuilder. Erhöhen wir ihn auf 100000 und werfen wir einen Blick darauf. Wir werden den Test für den String-Typ hier nicht hinzufügen, da das Testen eine so große Datenmenge für den String-Typ sein wird sehr langsam...
Die für die Ausführung des Typs java.lang.StringBuffer benötigte Zeit beträgt: 31 Millisekunden. Die für die Ausführung des Typs java.lang.StringBuilder benötigte Zeit beträgt: 16 Millisekunden
Sie können den Unterschied sehen, aber viele Testergebnisse zeigen, dass StringBuffer schneller ist als StringBuilder. Erhöhen wir den Wert auf 1000000 und sehen (es sollte nicht abstürzen, oder?):
Die für die Ausführung des Typs java.lang.StringBuffer benötigte Zeit beträgt: 265 Millisekunden. Die für die Ausführung des Typs java.lang.StringBuilder benötigte Zeit beträgt: 219 Millisekunden
Es gibt weniger Unterschiede und die Ergebnisse sind sehr stabil. Betrachten wir es etwas größer, ttime = 5000000:
Ausnahme im Thread „main“ java.lang.OutOfMemoryError: Java-Heap-Speicherplatz
Haha, vergiss es, ich werde es nicht mehr testen. Grundsätzlich ist die Leistung StringBuilder > StringBuffer > String.