0

According to my knowledge, we cannot use == operators to compare String values in Java. So I wrote the following code:

public class Test {
  public static void main(String[] args) {

    String s1 = "My Computer";
    String s2 = "My" + " Computer";

    System.out.println(s1 == s2);
  }
}

And I was expecting the result to be false because these are two different objects having assigned different memory locations (please correct me in this regard if I am wrong ). But when I executed the code, the output was true.

Then I changed the value of s2 as:

String str = "My";
String s2 = str + " Computer";      //instead of "My" + " Computer"

And then when I executed the code, the output was false.

Now I cannot understand the difference in these two statements, although I have used + (not the concat() method) in both statements. Can anyone explain, please.

swdeveloper
  • 908
  • 1
  • 11
  • 33

3 Answers3

2

Java uses a pool for String objects - it tries to be smart. This means that when the compiler can figure out that you actually have the same object, even the == on two seemingly different objects return true.

Nevertheless, it should be avoided to compare objects via == if you like to compare the content, as this only compares the object reference. For content comparison equals should be used.

Emerson Cod
  • 1,990
  • 3
  • 21
  • 39
2

There is a silly error in your test cases. String s2 = s1 + " Computer"; would assign s2 the string "My Computer Computer", not "My Computer".

For how to do String comparison Java, visit this link.

Why String is immutable in Java - an article explaining why instances of the String class in Java can not be modified. Read this for clarity.

Community
  • 1
  • 1
Sauhard Gupta
  • 219
  • 3
  • 10
2

What trips you up is this part of the specification:

The String object is newly created (§12.5) unless the expression is a constant expression (§15.28).

So when you concatenate a string constant to another string constant, that counts as a constant expression and therefore will be evaluated at compile time and replaced with the string constant "My Computer".

You can verify this by running javap -c on the compiled class.

public class Test {

    public static void main(String[] args) {

        String s1 = "My Computer";
        String s2 = "My" + " Computer";
        String s3 = "My";
        String s4 = s3 + " Computer";

        System.out.println(s1 == s2); //true
        System.out.println(s1 == s4); //false
    }
}

Which compiles to:

  public static void main(java.lang.String[]);
    Code:
       // s1 = "My Computer"
       0: ldc           #2                  // String My Computer
       2: astore_1

       // s2 = "My" + " Computer"
       3: ldc           #2                  // String My Computer
       5: astore_2

       // s3 = "My"
       6: ldc           #3                  // String My
       8: astore_3

       // s4 = s3 + " Computer"
       9: new           #4                  // class java/lang/StringBuilder
      12: dup
      13: invokespecial #5                  // Method java/lang/StringBuilder."<
init>":()V
      16: aload_3
      17: invokevirtual #6                  // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      20: ldc           #7                  // String  Computer
      22: invokevirtual #6                  // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      25: invokevirtual #8                  // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
      28: astore        4

      ... the rest of the code omitted 

As you can see, the first two assignments (to s1 and s2) load exactly the same constant (#2), and therefore use the same object. Whereas the assignment to s4 is not defined as a constant expression (even though a sufficiently clever compiler could figure it out, it is not allowed to), and therefore you get the whole "create a StringBuilder, append the strings to it, convert the result to a new string" process.

As an interesting aside, if in the code above you add the final modifier to s3, that makes s3 + " Computer" a constant expression again, and both comparisons will print true.

And as no doubt you already know, your code's correctness mustn't rely on all of this, but it's a fun thing to know.

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • So what I have understood from this is that when we use "+" operator with a string variable (NOT a literal) then new object is created? – swdeveloper Nov 19 '15 at 10:45
  • @swdeveloper It is slightly more complicated than that, I added a link to the definition of "constant expression", – biziclop Nov 19 '15 at 10:47
  • "As an interesting aside, if in the code above you add the final modifier to s3, that makes s3 + " Computer" a constant expression again, and both comparisons will print true" Great point! – swdeveloper Nov 19 '15 at 11:10
  • One more thing to clear about "pool of string objects" (because I have seen this phrase in may SO answers and other websites); Is it a fixed memory assigned to string objects? If yes, then how much size is assigned to it and what if there are so many string objects and the size of total string objects is larger than the assigned memory? – swdeveloper Nov 19 '15 at 11:11
  • @swdeveloper That should really be a separate question: the sizing and behaviour of the string pool differs between Java versions. But you can find a good overview [here](http://java-performance.info/string-intern-in-java-6-7-8/). – biziclop Nov 19 '15 at 11:48