Java Quiz 2

/wp-content/2007/java-time.jpeg

Yes, it's Java quiz time again.

"Everyone" knows you shouldn't compare strings by reference equality (==), but can you explain why...

public class Test1 {
    public static void main(String args[]) {
        System.out.println(("use" == "use") ? "True" : "False");
    }
}

...always prints 'True', and then...

public class Test2 {
    public static void main(String args[]) {
        System.out.println((new String("mention") == new String("mention")) ? "True" : "False");
   }
}

...always prints 'False'?

Comments (8)

mullet

This is vaguely interesting. A quick javap -c on Test1 tells us:

<code> 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String True
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return</code>

In otherwords javac is concluding that "use" is always equivalent to "use" (which I guess is a form of constant folding) and applying branch elimination to the inline if.

Clearly realising that 'new String("mention")' is equivalent to 'new String("mention")' is too hard or computationally expensive for javac to do.

Dec. 27, 2007, 3:55 a.m. #
lamby

Aw, you're so close; but by "always", I genuinely mean always. Also, your answer is implementation specific. :)

Dec. 27, 2007, 11:17 a.m. #
RobRob

*thinks he remembers some magic about this from somewhere*,

doesn't java have some magical pool of constant string objects? so, i'd guess if it finds a constant string that is already in the pool, it doesn't bother creating a new one and just points at the already created string object. (ie: both are the same string object)

as for why the second bit is always false, they're different string objects innit.

(do i get a prize?)

Dec. 27, 2007, 12:50 p.m. #
lamby

@RobRob
That's not a particularly convincing explanation.. You posit that it doesn't bother creating a new string when there's one already in the pool, but then you claim that they are different strings.. My question is really about the connection between the two: why one but not the other?

Dec. 27, 2007, 7:16 p.m. #
JT

Extending frrobrob om - in the first instance, the two are defined at the compile time and would be the same reference in the "string pool". The compiler would have to set these to being the same if pointer 1== pointer 1, if not actually compile all the way down and remove the if statement completely (as mullet observes))

In the second case, they string might be the same in the string pool, but the new keyword means that the reference to them are different. If you consider the reference to be effectively a pointer, the two are pointing at the same string, but they themselves are not the same.

Jan. 7, 2008, 3:44 p.m. #
Ed Davies

The second case is obvious, <i>new</i> creates new objects each time as it doesn't know about classes which have mostly pure value semantics (two strings with the same characters are indistinguishable except by "==" (and "!=", of course)). The first is a bit more subtle - you have to know that all the string constants are in the String#intern pool and so there's a single instance for each character sequence, sort of like if you'd written "new String("use").intern() == new String("use").intern()" which would return <i>true</i> each time.

Jan. 24, 2008, 12:20 p.m. #

From <a href="http://java.su…" rel="nofollow">Section 3.10.5 of the Java Language Specification</a>:

<blockquote>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.</blockquote>

Strings created with <code>new String</code> are new object instances and therefore have a different identity. Inline strings are interned and thus have the same identity.

Jan. 24, 2008, 3:47 p.m. #

False ...

System.out.println(("use".equals("use")) ? "True" : "False"); == true
System.out.println((new String("mention").equals("mention")) ? "True" : "False");

Returns true.

Feb. 11, 2008, 12:44 p.m. #