2

Possible Duplicate:
Questions about Java's String pool

String s1 = "length";
String s2 = "length";
System.out.println("EQUAL: " + (s1 == s2));
String s3 = "length: 10";
String s4 = "length: " + s3.length();
System.out.println(s3.length());
System.out.println(s4.length());
System.out.println("EQUAL: " + (s3 == s4));

Output :

EQUAL: true //Understood same string reference in string pool

10

10

EQUAL: false // Why?

Community
  • 1
  • 1
Dhananjay
  • 734
  • 1
  • 9
  • 14
  • 1
    @minitech Wrong. It's the duplicate of a duplicate of a duplicate of a (...) – Fritz Oct 02 '12 at 14:47
  • 4
    You might want to go through some of your other questions and see if you can accept some other answers. Your acceptance is how we get "paid" to answer your questions, and you're only paying out 20 cents on the dollar. – rajah9 Oct 02 '12 at 14:48
  • 1
    It's questions like this that convince me that the biggest mistake of Java designers was not adding a default override of the `==` operators for strings. – Sergey Kalinichenko Oct 02 '12 at 14:49
  • 1
    @dasblinkenlight yeah, or just go all the way with the "no pointer arithmetic" idea and get rid of == on references. A native `boolean System.sameObject(Object o1, Object o2)` would have worked fine. – yshavit Oct 02 '12 at 14:51
  • @dasblinkenlight: Definitely. I wonder what their justification is for that. IMHO, the whole handling of Strings through syntactical voodoo is clunky. – Wug Oct 02 '12 at 14:52
  • I think C# doesn't care whether it is == (or) .Equals() on Strings. Both behave same. May be same can be implemented here? – kosa Oct 02 '12 at 14:56
  • It's too late, @Nambari. There's code out there that relies on reference equality. – yshavit Oct 02 '12 at 15:09

3 Answers3

4
 String s4 = "length: " + s3.length();

Creates new String object.

So, s3 reference to different object and s4 references to different object, which makes == condition return false.

kosa
  • 65,990
  • 13
  • 130
  • 167
  • there is no 'new' operator. So everything must have been created in constant pool, which cannot have duplicate values? – Dhananjay Oct 02 '12 at 14:55
  • +1 the compiler simplifies Strings known at compile time. `s3.length()` is not a method call the compiler optimises/knows the result of at compile time. – Peter Lawrey Oct 02 '12 at 14:55
  • @Dhananjay: As Peter Lawrey explained, s3.length() can't be figured out at compile time, it is evaluated at runtime and creates new String object. – kosa Oct 02 '12 at 14:58
1

there is no 'new' operator. So everything must have been created in constant pool, which cannot have duplicate values?

String s4 = "length: " + s3.length();

is much the same as

String s4 = new StringBuilder().append("length: ")
                               .append(Integer.toString(s3.length()))
                               .toString();

so it creates quite a few new objects and a new String.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

"==" on objects (and arrays) is physical equality. That is, for objects a and b, a == b is true if a and b point to the same object.

The compiler does some optimizations for you. For example, the string "length" is only stored once as a constant. Hence s1 and s2 point to the same (constant) string.

Perhaps it will help to look at the outputted bytecode. Note that this is jasmin assembly code generated from a non-standard java compiler. You can confirm that the java compiler does something similar by running "javap -c" (the output is less readable, though).


Load reference to constant string "length" and store in s1.

ldc "length"
astore_1

Load reference to (the same) constant string "length" and store in s2.

ldc "length"
astore_2

Compare and print the result. It's not too readable.

getstatic java/lang/System/out Ljava/io/PrintStream;
new java/lang/StringBuffer
dup
invokespecial java/lang/StringBuffer/<init>()V
ldc "EQUAL: "
invokevirtual java/lang/StringBuffer/append(Ljava/lang/String;)Ljava/lang/StringBuffer;
aload_1
aload_2
if_acmpeq true0
iconst_0
goto end1
true0:
iconst_1
end1:
invokevirtual java/lang/StringBuffer/append(Z)Ljava/lang/StringBuffer;
invokevirtual java/lang/StringBuffer/toString()Ljava/lang/String;
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V

Load "length: 10" and store in s3

ldc "length: 10"
astore_3

Concatenate "length: " with the length and store in s4. Note that concatenating will create a new string (and hence a new reference).

new java/lang/StringBuffer
dup
invokespecial java/lang/StringBuffer/<init>()V
ldc "length: "
invokevirtual java/lang/StringBuffer/append(Ljava/lang/String;)Ljava/lang/StringBuffer;
aload_3
invokevirtual java/lang/String/length()I
invokevirtual java/lang/StringBuffer/append(I)Ljava/lang/StringBuffer;
invokevirtual java/lang/StringBuffer/toString()Ljava/lang/String;
astore 4

Print as before and return.


As you can see, the first two variables are referring to the same string in the "constant pool". The variable s3 is referring to a string in the constant pool, too, but s4 is referring to a new string built from a constant string and a number.

Btw, you shouldn't rely on this behavior.

ReyCharles
  • 1,772
  • 10
  • 30