2015-04-26 5 views
15

Wenn ich dieses Snippet kompiliere.Wie erfolgt die Verkettung der letzten Strings in Java?

public class InternTest { 
    public static void main(String...strings){ 
     final String str1="str"; 
     final String str2="ing"; 
     String str= str1+str2; 

    } 
} 

, das die folgende Bytecode

public static void main(java.lang.String...); 
    flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS 
    Code: 
    stack=1, locals=4, args_size=1 
     0: ldc   #16     // String str 
     2: astore_1 
     3: ldc   #18     // String ing 
     5: astore_2 
     6: ldc   #20     // String string 
     8: astore_3 
     9: return 

so Stringliteral "string" produziert, ist schon da in dem konstanten Pool, die 6: ldc #20 // String string auf Stapel an dieser Linie geschoben wird.

JSL Zitiert

Von JLS §4.12.4 - final Variablen:

Eine Variable vom Urtyp oder String-Typ, das ist endgültig und mit einem Kompilierung-konstanten Ausdruck initialisiert (§ 15.28), wird eine konstante Variable genannt.

Auch von JLS §15.28 - ConstantExpression:

Compile-Zeit konstanter Ausdrücke vom Typ String sind immer "interniert" um eindeutige Instanzen zu teilen, die Methode String # intern verwendet().

So weiß ich, str1 und str2 wird in dem Moment interniert werden sie erstellt wurde. „Str“ und „ing“ den gleichen Speicher in Zeile teilen String str= str1+str2; Aber wie str1 + str2 produziert direkt „string“ in der konstante String Pool. Ohne irgendeine String Builder-Klasse aufzurufen, wie wenn ich final nicht schreibe.? Um zu sehen, ob es etwas zu tun mit intern Dinge bekommen hat

ich diesen Schnipsel schrieb

public class IntermTest { 
    public static void main(String...strings){ 
     String str1=("str").intern(); 
     String str2=("ing").intern(); 
     String str= str1+str2; 

    } 
} 

Aber wenn ich den Bytecode erzeugt bekam ich dieses

public static void main(java.lang.String...); 
    flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS 
    Code: 
     stack=3, locals=4, args_size=1 
     0: ldc   #16     // String str 
     2: invokevirtual #18     // Method java/lang/String.intern: 
()Ljava/lang/String; 
     5: astore_1 
     6: ldc   #24     // String ing 
     8: invokevirtual #18     // Method java/lang/String.intern: 
()Ljava/lang/String; 
     11: astore_2 
     12: new   #26     // class java/lang/StringBuilder 
     15: dup 
     16: aload_1 
     17: invokestatic #28     // Method java/lang/String.valueOf 
:(Ljava/lang/Object;)Ljava/lang/String; 
     20: invokespecial #32     // Method java/lang/StringBuilder. 
"<init>":(Ljava/lang/String;)V 
     23: aload_2 
     24: invokevirtual #35     // Method java/lang/StringBuilder. 
append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
     27: invokevirtual #39     // Method java/lang/StringBuilder. 
toString:()Ljava/lang/String; 
     30: astore_3 
     31: return 

Tat es nutzt auch stringBuilder für Verkettung. Also hat es etwas mit Finale zu tun. Gibt es etwas Besonderes an final Saiten, denen ich definitiv nicht bewusst bin?

+0

Etwas sagt mir, dass dies die Antwort sein wird Ihre nächste Frage: http://Stackoverflow.com/a/19418517/1393766 – Pshemo

+0

@Pshemo, wenn dies klar geworden ist ..ich glaube nicht, dass das ein Problem verursacht hätte .. Wie auch immer, danke für so nette Frage .. :) Jede Frage ist eine große Lernkurve! –

Antwort

16

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28 sagt, dass

Einfache Namen (§6.5.6.1), die auf konstante Variablen beziehen (§4.12.4) sind konstante Ausdrücke.

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28 auch sagt:

Ein konstanter Ausdruck ist ein Ausdruck einen Wert von primitivem Typ oder ein String bezeichnet, die nicht abrupt nicht vervollständigen und besteht nur die Verwendung von folgend:

  • Literale des primitiven Typs und Literale des Typs String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)
  • [...]
  • Die additiven Operatoren + und - (§15.18)
  • [...]]
  • Einfache Namen (§6.5.6.1), die sich auf konstante Variablen beziehen (§4.12.4).

Beispiel 15.28-1. Konstante Ausdrücke

[...]

"Die ganze Zahl" + Long.MAX_VALUE + "ist mächtig groß."

Da diese beiden Variablen konstant Ausdrücke sind, hat der Compiler die Verkettung:

String str = str1 + str2; 

wird auf die gleiche Art und Weise zusammengestellt wie

String str = "str" + "ing"; 

, die die gleiche Art und Weise wie

kompiliert wird
String str = "string"; 
+0

Wenn der Compiler es tut, warum es bleibt in Byte-Code versteckt oder tut es es woanders, denn wenn ich nicht falsch bin Moderne Java-Compiler konvertieren meine + Operationen von 'StringBuilder append.'? –

+6

Wie gesagt, die Verkettung erfolgt durch den Compiler selbst, und nicht zur Laufzeit. Der für die Zeile 'String str = str1 + str2' erzeugte Byte-Code ist genau der gleiche Byte-Code wie der für die Zeile' String str = 'string' 'generierte Byte-Code, da' str1 + str2' ein konstanter Ausdruck ist. –

+3

"weil str1 + str2 ein konstanter Ausdruck ist" oder genauer gesagt, da 'str1' und' str2' nicht irgendwelche Konstanten sind, sondern * Kompilierzeitkonstanten *, die dem Compiler erlauben, ihn einmal zu berechnen und das Ergebnis in Code zu setzen bei jeder Ausführung dieses Codes zur Laufzeit neu berechnen. – Pshemo

Verwandte Themen