I\'ve got a question of some strange String pool behavior.
I\'m using ==
to compare equal Strings to find out whether they\'re in the pool or not.
p
In the second case the compiler COULD have recognized that + ""
is a no-op of sorts, since ""
is a compile-time value known to be zero length. But the compiler is still required to check the result from giveLiteralString
for null (since the null check would occur as a result of the +
operation in the non-optimized case), so it's simplest to just not attempt the optimization.
As a result, the compiler generates code to perform the concatenation, and a new string is created.
After decompiling this line
System.out.println("555" == "555" + "");
I got this bytecode
LINENUMBER 8 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ICONST_1
INVOKEVIRTUAL java/io/PrintStream.println(Z)V
...
which is equivalent to
System.out.println(true);
that means expression "555" == "555" + ""
compiles to boolean true
.
For giveLiteralString() == giveLiteralString() + ""
javac built this bytecode
LINENUMBER 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
...
which is equivalent to
if (giveLiteralString() == new StringBuilder(giveLiteralString()).append("").toString()) {
...
which will always produce false since here we're comparing 2 disctinct objects.
Compile Time Concatenation String computed by constant expression are done at compile time and treated as constants or literals means the value of the string or expression is known or evaluated at compile time hence the compiler can check the same value in string pool and the return the same string object reference.
Runtime Concatenation String expressions whose values are known or can not be evaluated at compile but depends on the input or condition of run-time then the compiler will not know the value of the string and hence always land up using StringBuilder to append the string and always returns a new string . I guess this example will clarify it better.
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() + "");
}
"555" + ""
is a compile-time constant, whereas
giveLiteralString() + ""
isn't. Therefore the former compiles into just the string constant "555" and the latter compiles into the actual method invocation and concatenation, resulting in a fresh String instance.
Strings computed by concatenation at run time are newly created and therefore distinct.