0

I am unable to recognize the difference in the following declarations of Strings in Java.

Suppose I am having two string

String str1="one";
String str2="two";

What is the difference between

String str3=new String(str1+str2);

and

String str3=str1+str2;

In both the above declarations, the content of str3 will be onetwo.

Suppose I create a new string

String str4="onetwo";

Then in none of the above declarations,

if(str4==str3) {
    System.out.println("This is not executed");
}

Why are str3 and str4 not referring to the same object?

Tiny
  • 27,221
  • 105
  • 339
  • 599
kevin gomes
  • 1,775
  • 5
  • 22
  • 30
  • 2
    Don't use `==` to compare strings – Apurva Mar 22 '15 at 18:59
  • @Apurva : I want to compare objects, not contents of strings. I want to know where `str4` and `str3` are referring – kevin gomes Mar 22 '15 at 19:00
  • this is actually comparing the reference that is if the str4 and str3 will points to the same location then it will equals which here is at different location.... instead use equal method of string – Iftikhar Ali Ansari Mar 22 '15 at 19:02
  • @Iftikhar Why and where str3 and str4 are referring to different location – kevin gomes Mar 22 '15 at 19:03
  • you can't print the address of an object in pure Java. http://stackoverflow.com/questions/18396927/how-to-print-the-address-of-an-object-if-you-have-redefined-tostring-method – Apurva Mar 22 '15 at 19:05
  • 1
    `Why and where str3 and str4 are referring to different location` Why do you think they should have the same reference? – Tom Mar 22 '15 at 19:11
  • @Tom because `String str3=str1+str2` should have been a interned string and `str4` should refer to the same location as `str3` – kevin gomes Mar 22 '15 at 19:17
  • 1
    @kevingomes "*because `String str3=str1+str2` should have been a interned*" no, compiler can't be sure of values of non-final variables so it can't concatenate them at compilation time like it can do in case of `"foo"+"bar"` and intern it. It will compile it into `new StringBuilder(str1).append(str2).toString()` and this result will not be interned. – Pshemo Mar 22 '15 at 19:19

4 Answers4

5

str1 + str2 for non-compilation-constant strings will be compiled into
new StringBuilder(str1).append(str2).toString(). This result will not be put, or taken from string pool (where interned strings go).

It is different story in case of "foo"+"bar" where compiler knows which values he works with, so he can concatenate this string once to avoid it at runtime. Such string literal will also be interned.

So String str3 = str1+str2; is same as

String str3 = new StringBuilder(str1).append(str2).toString();

and String str3 = new String(str1+str2); is same as

String str3 = new String(new StringBuilder(str1).append(str2).toString());

Again, strings produced as result of method (like substring, replace, toString) are not interned.
This means you are comparing two different instances (which store same characters) and that is why == returns false.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
3

Java does not have memory of "how this variable got the value", therefore it really does not matter which method you use, if the result is same.

About comparing, if you compare strings with ==, you are comparing address of objects in memory, because String is not primitive data type, not values. You have to use if(str4.equals(str3))

libik
  • 22,239
  • 9
  • 44
  • 87
  • I want to compare the address of the objects only.Wht str3 and str4 are having different references – kevin gomes Mar 22 '15 at 19:04
  • It matters which method we use – frunkad Mar 22 '15 at 19:07
  • @kevingomes - google : java tutorial. Actually you want to compare values, not address in memory, in your example. If your wife gives life to twins, they can look same, but they are two different instances. If you want to know, if they are look same, you use "equals", if you want to know, if they are same person, you use "==". – libik Mar 22 '15 at 19:07
3

Because Strings in Java are immutable the compiler will optimize and reuse String literals. Thus

String s1 = "one";
String s2 = "one";
s1 == s2; //true because the compiler will reuse the same String (with the same memory address) for the same string literal
s1 == "o" + "ne"; //true because "Strings computed by constant expressions are computed at compile time and then treated as if they were literals"
s3 = "o";
s1 == s3 + "ne"; //false because the second string is created a run time and is therefore newly created

for a reference see http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5

robertjlooby
  • 7,160
  • 2
  • 33
  • 45
  • You used the word `immutable` – frunkad Mar 22 '15 at 19:08
  • `may be true as the compiler may ...`? This will _always_ be true. – Tom Mar 22 '15 at 19:08
  • I believe that any compiler _will_ do this, so it will likely be true in practice. However I don't think this behavior is actually defined in the language standard so I didn't want to say that it would always be true as a valid compiler could have different behavior. – robertjlooby Mar 22 '15 at 19:11
  • Interning Strings has nothing to do with the compiler. – Tom Mar 22 '15 at 19:14
  • You're right, string literals will always be interned http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5 fixing it. – robertjlooby Mar 22 '15 at 19:22
0

Strings are kind of tricky, because there is some effort to share their representation. Plus they're immutable. The short answer is: unless you're really working in a low level, you should never compare strings using "==". Even if it works for you, it will be a nightmare for your teammates to maintain.

For a longer answer and a bit of amusement, try the following:

String s1= "a" + "b";
String s2= "a" + "b";
String s3=new String("a"+"b");

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

You'll notice that s1==s2 due to the compiler's effort to share. However s2 != s3 because you've explicitly asked for a new string. You're not likely to do anything very smart with it, because it's immutable.

Pelit Mamani
  • 2,321
  • 2
  • 13
  • 11