I run the following code and get the results shown in the comments. I know the differences between == and .equals(). What I don't understand is why my code in the second line has different results from the code in the third line.
String de = "de";
// String abcde = "abc" + "de"; // abcde == "abcde" reture true
String abcde = "abc" + de; // abcde == "abcde" reture false;
System.out.println();
System.out.println(abcde=="abcde");
System.out.println(de=="de");
In trying to debug this I used the javap -c command and got the following output 'code' for the first string concatenation:
Code:
0: ldc #9; //String de
2: astore_1
3: new #10; //class java/lang/StringBuilder
6: dup
7: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
10: ldc #4; //String abc
12: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang
String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #12; //Method java/lang/StringBuilder.append:(Ljava/lang
String;)Ljava/lang/StringBuilder;
19: invokevirtual #13; //Method java/lang/StringBuilder.toString:()Ljava/l
ng/String;
22: astore_2
23: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream;
26: invokevirtual #15; //Method java/io/PrintStream.println:()V
29: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream;
32: aload_2
33: ldc #16; //String abcde
35: if_acmpne 42
38: iconst_1
39: goto 43
42: iconst_0
43: invokevirtual #17; //Method java/io/PrintStream.println:(Z)V
46: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream;
49: aload_1
50: ldc #9; //String de
52: if_acmpne 59
55: iconst_1
56: goto 60
59: iconst_0
60: invokevirtual #17; //Method java/io/PrintStream.println:(Z)V
63: return
And the output for the second string concatenation:
I am not so familiar with this 'code' and can't see any reason why these differences exists. So could anyone explain why those differences happen?
Related post
The "problem" is simply that the compiler is too smart for you. When it sees "abc" + "de" it immediately concatenates that into the literal "abcde". But when it sees "abc" + de it's not allowed (per Java rules) to "optimize" that to a literal but must instead implement the + function, creating a new String object.
String literals are always handled as interned Strings, so == will work on them.
The problem isn't to do with the +, it's that you're comparing strings with ==.
Short answer: use "string".equals("string2")
In java == is a referential equals when used with objects (such as strings); "do these two names point at the same object in memory?"
Java has a string pool of common strings that it uses rather than creating a new object each time (which is not an issue as Strings are immutable), so your true/false issue is down to whether the compiler is clever enough to recognise that the two strings would be the same or not and that it can therefore use the same object. Don't rely on it.
String de = "de"; // "de" is set during compile time and placed in the "String Pool".
// String abcde = "abc" + "de";// abcde == "abcde" reture true -- > String reference abcde will be set to "abcde" during compilation itself. and "abcde" will be placed in the String Pool.
String abcde = "abc" + de; // abcde == "abcde" reture false; abcde will not be set during compilation as the value of reference de will be resolved during runtime.
System.out.println();
System.out.println(abcde=="abcde");// false as --> String literal "abcde" on String pool != String Object "abcde" on heap.
System.out.println(de=="de");// true--> de points to "de" on String pool
It's an artifact of the Java compiler. As you should know, == compares object references, it doesn't compare their contents.
The Java compiler interns bare strings seen in the source code. This is why "x"=="x", as there is only one copy of the "x" string, interned from the source code, but reading in a String from a file whose value is "x" will not == that interned "x", because it's not the same object.
The Java compiler is also clever about the + operator on Strings. It will internally convert var+"x" to new StringBuffer().append(var).append("x").toString(). But it will also join strings together and intern them as yet another string, e.g. "abc"+"de" will result in the interned string "abcde", not new StringBuffer().append("abc").append("de").toString().
Related
I have a simple question about strings in Java. The following segment of simple code just concatenates two strings and then compares them with ==.
String str1="str";
String str2="ing";
String concat=str1+str2;
System.out.println(concat=="string");
The comparison expression concat=="string" returns false as obvious (I understand the difference between equals() and ==).
When these two strings are declared final like so,
final String str1="str";
final String str2="ing";
String concat=str1+str2;
System.out.println(concat=="string");
The comparison expression concat=="string", in this case returns true. Why does final make a difference? Does it have to do something with the intern pool or I'm just being misled?
When you declare a String (which is immutable) variable as final, and initialize it with a compile-time constant expression, it also becomes a compile-time constant expression, and its value is inlined by the compiler where it is used. So, in your second code example, after inlining the values, the string concatenation is translated by the compiler to:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
which when compared to "string" will give you true, because string literals are interned.
From JLS §4.12.4 - final Variables:
A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.
Also from JLS §15.28 - Constant Expression:
Compile-time constant expressions of type String are always "interned" so as to share unique instances, using the method String#intern().
This is not the case in your first code example, where the String variables are not final. So, they are not a compile-time constant expressions. The concatenation operation there will be delayed till runtime, thus leading to the creation of a new String object. You can verify this by comparing byte code of both pieces of code.
The first code example (non-final version) is compiled to the following byte code:
Code:
0: ldc #2; //String str
2: astore_1
3: ldc #3; //String ing
5: astore_2
6: new #4; //class java/lang/StringBuilder
9: dup
10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9; //String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
42: return
Clearly it is storing str and ing in two separate variables, and using StringBuilder to perform the concatenation operation.
Whereas, your second code example (final version) looks like this:
Code:
0: ldc #2; //String string
2: astore_3
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2; //String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
So it directly inlines the final variable to create String string at compile time, which is loaded by ldc operation in step 0. Then the second string literal is loaded by ldc operation in step 7. It doesn't involve creation of any new String object at runtime. The String is already known at compile time, and they are interned.
As per my research, all the final String are interned in Java. From one of the blog post:
So, if you really need to compare two String using == or != make sure you call String.intern() method before making comparison. Otherwise, always prefer String.equals(String) for String comparison.
So it means if you call String.intern() you can compare two strings using == operator. But here String.intern() is not necessary because in Java final String are internally interned.
You can find more information String comparision using == operator and Javadoc for String.intern() method.
Also refer this Stackoverflow post for more information.
If you take a look at this methods
public void noFinal() {
String str1 = "str";
String str2 = "ing";
String concat = str1 + str2;
System.out.println(concat == "string");
}
public void withFinal() {
final String str1 = "str";
final String str2 = "ing";
String concat = str1 + str2;
System.out.println(concat == "string");
}
and its decompiled with javap -c ClassWithTheseMethods
versions you will see
public void noFinal();
Code:
0: ldc #15 // String str
2: astore_1
3: ldc #17 // String ing
5: astore_2
6: new #19 // class java/lang/StringBuilder
9: dup
10: aload_1
11: invokestatic #21 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
14: invokespecial #27 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
17: aload_2
18: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
...
and
public void withFinal();
Code:
0: ldc #15 // String str
2: astore_1
3: ldc #17 // String ing
5: astore_2
6: ldc #44 // String string
8: astore_3
...
So if Strings are not final compiler will have to use StringBuilder to concatenate str1 and str2 so
String concat=str1+str2;
will be compiled to
String concat = new StringBuilder(str1).append(str2).toString();
which means that concat will be created at runtime so will not come from String pool.
Also if Strings are final then compiler can assume that they will never change so instead of using StringBuilder it can safely concatenate its values so
String concat = str1 + str2;
can be changed to
String concat = "str" + "ing";
and concatenated into
String concat = "string";
which means that concate will become sting literal which will be interned in string pool and then compared with same string literal from that pool in if statement.
Stack and string conts pool concept
Let's see some byte code for the final example
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: ldc #2 // String string
2: astore_3
3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2 // String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4 // Method java/io/PrintStream.println:(Z)V
20: return
}
At 0: and 2:, the String "string" is pushed onto the stack (from the constant pool) and stored into the local variable concat directly. You can deduce that the compiler is creating (concatenating) the String "string" itself at compilation time.
The non final byte code
Compiled from "Main2.java"
public class Main2 {
public Main2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: ldc #2 // String str
2: astore_1
3: ldc #3 // String ing
5: astore_2
6: new #4 // class java/lang/StringBuilder
9: dup
10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
17: aload_2
18: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9 // String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
42: return
}
Here you have two String constants, "str" and "ing" which need to be concatenated at runtime with a StringBuilder.
Though, when you create using String literal notation of Java, it automatically call intern() method to put that object into String pool, provided it was not present in the pool already.
Why does final make a difference?
Compiler knows the final variable never gonna change, when we add these final variables the output goes to String Pool because of str1 + str2 expression output also never gonna change, So finally compiler calls inter method after output of the above two final variables. In case of non-final variable compiler do not call intern method.
public static void main(String[] args) {
String a = new String("lo").intern();
final String d = a.intern();
String b = "lo";
final String e = "lo";
String c = "Hello";
System.out.println(b==a);//true
System.out.println(d==a);//true
System.out.println(e==a);//true
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
System.out.println(c=="Hel"+e); //this is true
}
This results in
true
true
true
false
false
false
true
The expression e==a is true implies same reference. So why the last expression is true but the 4th to last ie c== "Hel"+a is false?
The expression
"Hel" + a
Is not a compile time constant. Actually, it compiles to:
new StringBuilder().append("Hel").append(a).toString()
(or similar) which creates a new String object at runtime.
However, because e is final, the compiler can determine that the concatenation of "Hel" and e's value is a constant value, and so interns it.
all these strings are calculated in runtime, this is why they are different
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
this one calculated during compile time, because e is final:
System.out.println(c=="Hel"+e); //this is true
if you change code to this:
System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true
System.out.println(c==("Hel"+d).intern()); //why is this false?
System.out.println(c==("Hel"+b).intern()); //why is this false?
all of them will produce true
Java compiler (javac) translates your code in Java to byte code which is executed by the JVM.
It also does some optimizations for you. You can check the generated byte code using javap utility with -c parameter
Concatenation with final String
c==a is true because c is final
Here is the byte code for this snippet (last comparison only):
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String Hello
2: astore_2
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_2
7: ldc #2; //String Hello
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
}
As you see the java compiler has merged the "Hel" with "lo" and just comparing two string leterals "Hello". Java interns string literals by default - that's why it returns true
Concatenation with non-final String
If you are concatenating the string literal with non-final String variable, the byte code will be different:
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String lo
2: astore_1
3: ldc #3; //String Hello
5: astore_2
6: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_2
10: new #5; //class java/lang/StringBuilder
13: dup
14: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
17: ldc #7; //String Hel
19: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: if_acmpne 36
32: iconst_1
33: goto 37
36: iconst_0
37: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
40: return
}
Here we are comparing the result of java/lang/StringBuilder.toString:()Ljava/lang/String; method which obviously returns another object - it is equal to "Hello" by value but not by reference
You can find more details on comparing strings in this stackoverflow question
Even though you are using intern() method, you have to still remember that == compares by reference and not value.
So in the cases of
System.out.println(c=="Hel"+a);
System.out.println(c=="Hel"+d);
System.out.println(c=="Hel"+b);
"Hel" + a or "Hel" + d or "Hel" + b will have a new reference in memory that is not equal to that of c.
in the final case since the string value is final, the evaluation happens at compile time instead of runtime as optimization since it will never change. Also if you are thinking when you define string literal, Java internally interns them.
Can anyone please explain what is the difference between below implementation of String-
1)
{
String comma=",";
return finalStr = "Hello"+comma+"Welcome"+comma+"to"+comma+"Stack"+comma+"overflow";
}
2)
{
return finalStr = "Hello,Welcome,to,Stack,overflow";
}
How many string object will be created in first (1) block, will there be only one string finalStr which refer to memory location where Hello,Welcome,to,Stack,overflow is stored or will it create multiple locations for each word and then once appended it will create a new memory location.
In both cases, only one String object will be created for each. Since, compiler is smart enough for understand the concatenation in compile time. These are string literals, they will be evaluated at compile time and only one string will be created for each cases.
As per JLS
A long string literal can always be broken up into shorter pieces and
written as a (possibly parenthesized) expression using the string
concatenation operator + [...] Moreover, a string literal always
refers to the same instance of class String.
Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
Strings computed by concatenation at run-time are newly created and therefore distinct.
Take a look at this or this answer. The compiler will optimize some things for you. So stick with the most readable solution.
Similar questions have been asked several times, you will find some useful further information about your question if you read those answers.
use javap to check how the compiler is trying to optimize the code, i first scenario, a concatenation happen using the StringBuilder and finally toString is called
Code:
0: ldc #16 // String ,
2: astore_1
3: new #18 // class java/lang/StringBuilder
6: dup
7: ldc #20 // String Hello
9: invokespecial #22 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
12: aload_1
13: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: ldc #29 // String Welcome
18: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: aload_1
22: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: ldc #31 // String to
27: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: ldc #33 // String Stack
36: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: aload_1
40: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: ldc #35 // String overflow
45: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
48: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
51: astore_2
Scenario 2
52: ldc #41 // String Hello,Welcome,to,Stack,overflow
54: astore_2
55: return
As far as I know,
In first cast JVM continuously making instant variables to keep Strings like "Hello", "Welcome", etc...
Further more, every appending operation it needs another variable to save appended String for example "Hello," + "Welcome" ...
On the other hand, second case, it allocate once for String. Thanks.
why "abc" + null results abcnull
String s1 = "abc";
String s2 = null;
String s3 = s1+ s2;
System.out.println(s3);
Result: abcnull
Because Java will create a StringBuilder to append s1, or "abc", to s2, or null.
According to the spec for StringBuilder.append(String)--
If str is null, then the four characters "null" are appended
So it turns into the same as "abc" + "null"
Let's take your code example (I placed it inside a method):
public static void main(String[] args)
{
String s1 = "abc";
String s2 = null;
String s3 = s1+ s2;
System.out.println(s3);
}
If we take a gander at the bytecode (gotten by invoking javap -c):
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String abc
2: astore_1
3: aconst_null
4: astore_2
5: new #3; //class java/lang/StringBuilder
8: dup
9: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
12: aload_1
13: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: aload_2
17: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: invokevirtual #6; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
23: astore_3
24: getstatic #7; //Field java/lang/System.out:Ljava/io/PrintStream;
27: aload_3
28: invokevirtual #8; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: return
Java creates a StringBuilder and appends the values, as Strings, of s1 and s2.
So you have to be careful then, if you were expecting a NullPointerException, because concatenation in Java will skirt the issue.
Side Note: As pointed out by Jon Skeet, this is ultimately just implementation details -- it's the Java spec that guarantees that null, when converted to a String, turns into "null". However, this bytecode at least shows what is actually happening behind the scenes.
That's exactly the value that's guaranteed by the language specification. From the JLS section 15.8.1.1, which talks about the string conversions used for string concatenation:
Now only reference values need to be considered. If the reference is null, it is converted to the string "null" (four ASCII characters n, u, l, l). Otherwise, the conversion is performed as if by an invocation of the toString method of the referenced object with no arguments; but if the result of invoking the toString method is null, then the string "null" is used instead.
(You may be interested to hear that .NET takes a different approach, converting a null reference to an empty string. Each approach has its pros and cons - I find the Java approach more useful for creating a string for debugging, but the .NET approach more useful when building a string to be displayed to a user or saved to a data file etc.)
That's how string concatenation works.
If you need to avoid concatenating the word "null" you can do:
String s3 = (s1==null?"":s1) + (s2==null?"":s2);
i don't know java, but from the looks of it, it seems like you are type casting s2 as a String object which then turns null into "null". Please correct me if i'm wrong.
String s = "a" + null;
compiler understands it as
String s = "a" + String.valueOf(null)
so
String s = "a" + String.valueOf(null)/* null*/ = "anull";
In your example
String s3 = String.valueOf(s1) + String.valueOf(s2);
s3 = "abc" + "null" // absnull
String Concatenation in Java executes automatic conversion. The null string will be converted to the string 'null'. For reference, see f.e. this page:
A null operand is converted to the
string literal "null".
To avoid this, you should check if one string is null yourself.
This is how Java Concatenation works.
It treats null objects as "null".
Please see this link
it is because any thing u add it with a string will by default convert it into a string.
and even if you try to add a number to a string it will be converted into string.
example:
"abc"+123="abc123"
there is a syntax called concat which will add only string to string not any thing else.
example :
if u type
"abc".concat(null)
then it will show
java.lang.NullPointerException
at java.lang.String.concat(Unknown Source)
but if u type
"abc".concat("null")
the output will be "abcnull".
Let's compile your code and look at the bytecode:
// -- Initialization of s1
5: ldc #2; //String abc
7: putfield #3; //Field s1
// ...
// -- Initialization of s2
11: aconst_null
12: putfield #4; //Field s2
// ...
// -- Initialization of s3
// create a StringBuilder
16: new #5; //class StringBuilder
19: dup
20: invokespecial #6; //Method StringBuilder."<init>"
// Load s1
23: aload_0
24: getfield #3; //Field s1
// Call StringBuilder.append(String)
27: invokevirtual #7; //Method StringBuilder.append(String)
30: aload_0
// Load s2
31: getfield #4; //Field s2
// Call StringBuilder.append(String)
34: invokevirtual #7; //Method StringBuilder.append(String)
// Get content of StringBuilder
37: invokevirtual #8; //Method StringBuilder.toString()
// Store in s3
40: putfield #9; //Field s3
So how does "null" end up in the result? Well, this is described in the documentation of StringBuilder.append(String):
The characters of the String argument are appended, in order, increasing the length of this sequence by the length of the argument. If str is null, then the four characters "null" are appended.
As Jon Skeet points out, this is all in accordance with the Java Language Specification.
1.
static final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
2.
System.out.println("Efficiently stored String");
Will Java compiler treat both (1 and 2) of these in the same manner?
FYI: By efficiently I am referring to runtime memory utilization as well as code execution time. e.g. can the 1st case take more time on stack loading the variable memFriendly?
This is covered in the Java Language Spec:
Each string literal is a reference
(§4.3) to an instance (§4.3.1, §12.5)
of class String (§4.3.3). String
objects have a constant value. String
literals-or, more generally, strings
that are the values of constant
expressions (§15.28)-are "interned" so
as to share unique instances, using
the method String.intern.
You can also see for yourself using the javap tool.
For this code:
System.out.println("Efficiently stored String");
final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
javap gives the following:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String Efficiently stored String
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: ldc #3; //String Efficiently stored String
13: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
public static void main(String[] args) {
System.out.println("Hello world!");
String hola = "Hola, mundo!";
System.out.println(hola);
}
Here is what javap shows as the disassembly for this code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String Hello world!
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //String Hola, mundo!
10: astore_1
11: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
14: aload_1
15: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
18: return
Looks like the second string is being stored, whereas the first one is simply passed to the method directly.
This was built with Eclipse's compiler, which may explain differences in my answer and McDowell's.
Update: Here are the results if hola is declared as final (results in no aload_1, if I'm reading this right then it means this String is both stored and inlined, as you might expect):
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String Hello world!
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //String Hola, mundo!
10: astore_1
11: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
14: ldc #30; //String Hola, mundo!
16: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
19: return
In this case, the compiler will handle both the same.
Anytime a String is defined at compile time, Java will optimize the storage of Strings.
If a string is defined at runtime, Java has no way of doing the same optomization.
The code you have is equivilant because string literals are automatically interned by the compiler.
If you are really concerned about String performance and will be reusing the same strings over and over you should take a look at the intern method on the string class.
http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()