Betrachten wir eine Frage zu String in Java: den Unterschied zwischen "ABC" + '/' und "ABC" + "/". In diesem Beispiel können wir die Verwendung von Javap in JDK -Tools üben. Die ursprüngliche Frage lautet wie folgt:
Was ist der Unterschied zwischen der Behandlung von Schrägstrichen/als Zeichen oder Zeichenfolgen?
Einer wird als grundlegender Datentyp -Zeichen verwendet, der andere ist die Objektzeichenfolge. Was ist der spezifische Unterschied?
Wird es effizienter sein, es als Charakter zu behandeln?
String str = "abc" + '/';
Und
String str = "abc" + "/";
1. Compiler -Optimierung
Erstens sollten Sie wissen, dass die beiden oben genannten Sätze den gleichen Effekt haben, da der Compiler die beiden oben genannten Sätze in Folgendes optimiert:
String str = "abc/";
Wir können dies durch Javap beweisen. Für Javap können wir uns auf "5 JDK -Tools, die jeder Java -Entwickler kennen" beziehen. Wir erstellen zuerst eine Klasse: StringOne und füllen den folgenden Code in der Hauptmethode aus:
StringOne.javastring str1 = "abc" + '/'; String str2 = "abc" + "/"; System.out.println(str1 == str2);
Kompilieren und ausführen, das Ausgabeergebnis ist wahr. Als nächstes wird unser Javap gestartet. Geben Sie den folgenden Befehl in die Befehlszeile ein:
javap -v -l stringOne.class> stringOne.s
Überprüfen Sie dann die generierte StringOne.s -Datei. Sie werden feststellen, dass es mehrere Zeilen enthält
StringOne.s #2 = String #20 // abc /...# 20 = utf8 ABC/... 0: LDC #2 // String ABC/2: Store_13: LDC #2 // String ABC/5: Store_2
Erläuterung: STR1 und STR2 beziehen sich beide auf die Zeichenfolge "ABC/".
2. Verwenden Sie Javap, um Unterschiede zu analysieren
Ändern wir nun die Frage. Was ist der Unterschied zwischen StringAddString und StringAddChar -Methoden im folgenden Code?
StringTWopublic Static StringAddString (String Str1, String Str2) {return str1 + str2;} public static String StringAddar (String Str, char ch) {return str + ch;}Dieses Mal wird Javap zur Dekompilierung verwendet, und ein Teil des Inhalts der generierten Datei lautet wie folgt
StringTwo.spublic Java.lang.String StringAddString (Java.lang.String, Java.lang.String); Deskriptor: (ljava/lang/string; ljava/lang/string;) ljava/lang/string; Flags: ACC_PUBLIC CODE: STACK = 2, LOCALS = 3, Args_size = 3 0: Neu #2 // Klasse Java/Lang/StringBuilder 3: DUP 4: Invokespecial #3 // Methode Java/Lang/StringBuilder. append: (ljava/lang/string;) ljava/lang/stringBuilder; 11: ALOAD_2 12: InvokeVirtual #4 // Methode Java/Lang/StringBuilder. append: (ljava/lang/string;) ljava/lang/stringBuilder; 15: InvokeVirtual #5 // Methode Java/Lang/StringBuilder. toString :() ljava/lang/string; 18: Areturnpublic Java.lang.String Stringaddchar (Java.lang.String, Char); Deskriptor: (ljava/lang/string; c) ljava/lang/string; Flags: ACC_PUBLIC CODE: STACK = 2, LOCALS = 3, Args_Size = 3 0: Neu #2 // Klasse Java/Lang/StringBuilder 3: DUP 4: Invokespecial #3 // Methode Java/Lang/StringBuilder. Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/StringBuilder; 11: Iload_2 12: InvokeVirtual #6 // Methode Java/Lang/StringBuilder.Append: (c) ljava/lang/StringBuilder; 15: InvokeVirtual #5 // Methode Java/Lang/StringBuilder.toString :() Ljava/Lang/String; 18: Areturn
Jetzt können wir den Prozess der Ausführung dieser beiden Methoden deutlich sehen:
StringAddString
Die Prozedur von StringAddChar entspricht der StringAddString, außer dass, wenn die Anhangsmethode als zweites Mal bezeichnet wird, der Parameter von StringAddString vom Zeichenstreichtyp ist, während der Parameter von StringAddChar vom Zeichen ist.
3. METHODE (STRING) -Methode (Zeichenanhang) der StringBuilder -Klasse (Stringbuilder -Klasse)
Hier müssen wir nur den Quellcode direkt überprüfen (meine ist der Quellcode, der mit JDK1.8.0_60 ausgestattet ist). Beachten Sie, dass das Dokument zwar zeigt, dass StringBuilder vom Objekt aus dem Quellcode ererbt, es jedoch aus der abstrakten AbstractStringBuilder der abstrakten Klasse vererbt wird. Und die Anhangsmethode wird von AbstractStringBuilder implementiert.
AbstractStringBuilder.java
public AbstractStringBuilder append (char c) {sealecapacityInternal (count + 1); // Stellen Sie sicher, dass das Array den Wert+1 -Zeichen Wert [count ++] = C aufnehmen kann; zurücksenden;} public AbstractStringBuilder append (string str) {if (str == null) return appendnull (); int len = str.length (); sealEcapacityInternal (count + len); Str.Getchars (0, Len, Wert, Graf); // Kopieren Sie das Zeichenarray in der Zeichenfolge in das Zeichenarray dieser Objektzahl += len; Gibt dies zurück;}Der Rest wird nicht mehr veröffentlicht. String.getchars (int, int, char [], int) hängt letztendlich von öffentlichen statischen nativen void Arraycopy (Objekt, int, Objekt, int, int) ab. Mit anderen Worten, es kann in C -Sprache geschrieben werden, und die Effizienz sollte beim Kopieren großer Arrays besser sein als in Java geschriebene Programme. Lassen Sie mich jetzt sagen, was ich verstehe:
In Bezug auf den direkten Speicher sollte das Array, da String char -Arrays enthält, Längenfelder. Gleichzeitig verfügt die String -Klasse über eine Int -Hash -Eigenschaft, und das Objekt selbst belegt zusätzlichen Speicher, um andere Informationen zu speichern, sodass die Zeichenfolge mehr Speicher belegt. Wenn die Zeichenfolge jedoch sehr lang ist, können diese Speicheraufwand fast ignoriert werden. Und wenn die Zeichenfolge (sehr) kurz ist, ist es sehr wahrscheinlich, dass es viele gemeinsame Verweise gibt, um diese Speicheraufwand zu teilen, sodass der überschüssige Speicheraufwand immer noch ignoriert werden kann.
Aus dem Anrufstack, da String nur ein oder zwei weitere Funktionsaufrufe als char hat, sollte der Funktionsaufrufaufenthalt (einschließlich Zeit und Platz) nicht in Betracht gezogen werden, sondern auch ähnlich sein. Wenn der Funktionsaufruf -Overhead berücksichtigt wird, sollte "ABC" + '/' besser sein; Wenn jedoch mehrere Zeichen verbunden werden müssen (ich denke, diese Situation sollte häufiger sein, oder?), Da die Verwendung von char viele Schleifen erfordert, um die Verbindung zu vervollständigen, wird die Anzahl der bezeichneten Funktionen nur als die Verwendung von String genannt. Gleichzeitig ist das Kopieren nicht schneller als die String direkt kopiert ein Array. Zu diesem Zeitpunkt wird es also zu "ABC" + "/" mit einem größeren Durchsatz.
Jetzt denke ich, dass diese Frage stellt: Ist es effizienter, Systemanrufe beim Lesen und Schreiben von Dateien zu verwenden, oder ist es effizienter, die IO -Bibliothek in der Standardfunktionsbibliothek zu verwenden. Ich persönlich bin der Meinung, dass die Standard-IO-Bibliothek zwar am Ende Systemanrufe aufrufen muss und einige vorübergehende Variablen und tiefere Anrufstapel aufgrund der Puffermechanismen der IO-Bibliothek generiert werden, der Durchsatz der IO-Bibliothek wird größer sein und die Echtzeitleistung von Systemanrufen wird besser sein. Obwohl die String -Klasse mehr Felder und einen tieferen Funktionsstapel hat, sollte der Durchsatz aufgrund des Cache und des direkteren Kopierens besser sein.
Neue Fragen
Nach dem oben genannten Javap -Dekompilierungscode zu urteilen, werden sie in StringBuilder angehängt, wenn die beiden Zeichenfolgen addiert werden. Welcher der folgenden Code ist theoretisch effizienter?
String str1 = "abc" + "123"; // 1StringBuilder StringBuilder = new StringBuilder (); // 2stringbuilder.Append ("ABC"); StringBuilder.Append ("123"); String str2 = StringBuilder.toString ();Lassen Sie diese Frage für alle nachdenken!
Das obige ist der gesamte Inhalt dieses Artikels, mit dem Sie String+String und String+CHAR in Java besser unterscheiden können. Ich hoffe, es wird für das Lernen aller hilfreich sein.