7

Possible Duplicate:
If == compares references in Java, why does it evaluate to true with these Strings?
String comparision with logical operator in Java

public static void main(String[] args) 
{
  String a = "ab";
  final String bb = "b";
  String b = "a" + bb;
  System.out.println(a == b);
}

why it print true??

but,

public static void main(String[] args)
{
  String a = "ab";
  String bb = "b";
  String b = "a" + bb;
  System.out.println(a==b);
}

it print false.

Community
  • 1
  • 1
HiMing
  • 365
  • 3
  • 14

4 Answers4

7

You're seeing the result of two things working in combination:

  1. The compiler is processing the "a" + bb at compile-time rather than runtime, because the bb is final and so it knows it can do that. (There are other times it knows that, too.)

  2. All strings generated by the compiler are interned. For more about interning, see this answer to another StackOverflow question about == in Java.

So the result is that a and b point to the same string instance, and so == returns true.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
6

Compiler computes string at compile time as it is final and will never change.

final String bb = "b";
String b = "a" + bb;

"a" + bb is evaluated at compile time

michael nesterenko
  • 14,222
  • 25
  • 114
  • 182
5

Java will intern string constants (final strings) and literals (create one instance of each string in an internal pool) and thus you might get the same instance, even if it is "created" by concatenation.

And as the others already stated, compiler optimization would actually turn the concatenation into one literal ("ab").

You can never fully rely on the == semantics of String, that's why you should always use equals(..).

Edit: to clarify the above sentence:

With objects == always means that the references are compared and it will always return true if both references are the same. However, you can't always rely on getting the same reference of an object (like in your example where a simple final changes behavior or in frameworks like Hibernate etc.) - that's why you generally should use equals(...) instead.

Of course you can use == if you need physical equality (the very same object) instead of logical equality (the same value).

Another example where == would have different results, although from a locical point of view both should be true:

Integer l1 = 0;
Integer l2 = 0;
l1 == l2; //most often true, since Integer objects up to 127 are cached

Integer l1 = 1000;
Integer l2 = 1000;
l1 == l2; //most often false, since those are not cached anymore

Note that with "most often" I mean that this could change between Java versions (if not different JVMs), although that's not very likely.

Thomas
  • 87,414
  • 12
  • 119
  • 157
  • 2
    *"You can never fully rely on the `==` semantics of String"* Sure you can, just as you can with any other **reference** type. `==` will be `true` if the references point to the same instance, and `false` if they don't. `equals` is about something else entirely. – T.J. Crowder Sep 26 '11 at 11:24
  • @T.J. what I meant is: you don't always know whether you get the same reference of a string or not, that's why you can't rely on the semantics. (The same applies to `Integer` as well). – Thomas Sep 26 '11 at 11:28
4

The JLS specifies this in the section about String Literals:

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.

Thus, the test program consisting of the compilation unit (§7.3):

package testPackage;
class Test {
    public static void main(String[] args) {
            String hello = "Hello", lo = "lo";
            System.out.print((hello == "Hello") + " ");
            System.out.print((Other.hello == hello) + " ");
            System.out.print((other.Other.hello == hello) + " ");
            System.out.print((hello == ("Hel"+"lo")) + " ");
            System.out.print((hello == ("Hel"+lo)) + " ");
            System.out.println(hello == ("Hel"+lo).intern());
    } }

class Other { static String hello = "Hello"; }

and the compilation unit:

package other;
public class Other { static String hello = "Hello"; }

produces the output:

true true true true false true

BTW: OMM (jdk1.6.0_21, Ubuntu), the above code doesn't compile until I make other.Other.hello public and then it outputs:

true true true true true true

Update: nope, my fault. My IDE automatically added final to the local variable declaration. If I remove that, I get:

true true true true false true
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588