Ich habe eine Frage zu einem seltsamen Verhalten des String-Pools. Ich verwende ==
, um gleiche Zeichenfolgen zu vergleichen, um herauszufinden, ob sie im Pool sind oder nicht.
public class StringPoolTest {
public static void main(String[] args) {
new StringPoolTest().run();
}
String giveLiteralString() {
return "555";
}
void run() {
String s1 = giveLiteralString() + "";
System.out.println("555" == "555" + "");
System.out.println(giveLiteralString() == giveLiteralString() + "");
}
}
Die Ausgabe ist:
true
false
Das ist eine große Überraschung für mich. Könnte jemand dies bitte erklären? Ich denke, etwas darüber findet zur Kompilierungszeit statt. Aber warum macht das Hinzufügen ""
zu einem String überhaupt einen Unterschied?
intern()
. B. via ).Antworten:
"555" + ""
ist eine Kompilierungszeitkonstante , während
giveLiteralString() + ""
ist nicht. Daher wird erstere nur in die Zeichenfolgenkonstante "555" kompiliert und letztere in den tatsächlichen Methodenaufruf und die Verkettung, was zu einer neuen Zeichenfolgeninstanz führt.
Siehe auch JLS §3.10.5 (String Literals) :
quelle
"555"+""
zu einem einzelnen Zeichenfolgenobjekt kombiniert."555"
While befindetmethod()+""
sich nochmethod()+""
nach der Kompilierung.final
zugiveLiteralString()
, wäre es etwas ändern?Nach dem Dekompilieren dieser Zeile
System.out.println("555" == "555" + "");
Ich habe diesen Bytecode bekommen
LINENUMBER 8 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; ICONST_1 INVOKEVIRTUAL java/io/PrintStream.println(Z)V ...
das ist äquivalent zu
System.out.println(true);
Das bedeutet, dass Ausdruck
"555" == "555" + ""
zu Booleschen Werten kompiliert wirdtrue
.Für
giveLiteralString() == giveLiteralString() + ""
javac wurde dieser Bytecode erstelltLINENUMBER 8 L0 INVOKESTATIC Test1.giveLiteralString()Ljava/lang/String; NEW java/lang/StringBuilder DUP INVOKESTATIC Test1.giveLiteralString()Ljava/lang/String; INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String; INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; IF_ACMPNE L1 ...
das ist äquivalent zu
if (giveLiteralString() == new StringBuilder(giveLiteralString()).append("").toString()) { ...
Das wird immer falsch sein, da wir hier 2 verschiedene Objekte vergleichen.
quelle
intern
.Im zweiten Fall hätte der Compiler erkennen können, dass
+ ""
es sich um eine Art No-Op handelt, da""
ein Wert zur Kompilierungszeit bekanntermaßen eine Länge von Null hat. Der Compiler muss das Ergebnis jedoch weiterhin aufgiveLiteralString
Null prüfen (da die Nullprüfung+
im nicht optimierten Fall als Ergebnis der Operation erfolgen würde). Daher ist es am einfachsten, die Optimierung einfach nicht zu versuchen.Infolgedessen generiert der Compiler Code, um die Verkettung durchzuführen, und eine neue Zeichenfolge wird erstellt.
quelle
Verkettung der Kompilierungszeichenfolge Durch konstante Ausdrücke berechnete Zeichenfolgen werden zur Kompilierungszeit ausgeführt und als Konstanten oder Literale behandelt. Dies bedeutet, dass der Wert der Zeichenfolge oder des Ausdrucks zur Kompilierungszeit bekannt ist oder ausgewertet wird. Daher kann der Compiler denselben Wert im Zeichenfolgenpool überprüfen und denselben zurückgeben String-Objektreferenz.
Runtime Concatenation String-Ausdrücke, deren Werte bekannt sind oder beim Kompilieren nicht ausgewertet werden können, aber von der Eingabe oder Bedingung der Laufzeit abhängen, dann kennt der Compiler den Wert des Strings nicht und landet daher immer mit StringBuilder, um den String anzuhängen, und immer gibt eine neue Zeichenfolge zurück. Ich denke, dieses Beispiel wird es besser verdeutlichen.
public static void main(String[] args) { new StringPoolTest().run(); } String giveLiteralString() { return "555"; } void run() { System.out.println("555" + 9 == "555" + 9); System.out.println("555"+Integer.valueOf(9) == "555" + Integer.valueOf(9)); System.out.println(giveLiteralString() == giveLiteralString()); // The result of runtime concatenation is a fresh string. System.out.println(giveLiteralString() == giveLiteralString() + ""); }
quelle