Egg_Egg
Egg_Egg

Reputation: 177

String comparison confused

Before we move on: I understand we should use .equals() to compare content. I am now just talking about if the actual references are the same for the following scenario...

Say we have the following:

String str1 = "str";
String str2 = "string";
String str3 = "ing";
String str4 = str1 + str3;
str1 = str4;
String str5 = "string";
System.out.println(str1==str2);//false

I think it supposed to be true since in the String pool, the reference to "string" should be the same, as str1 and str2, now are both "string". It should be true, but ends up as false.

System.out.println(str1.intern()==str2.intern());//true

I tried this, and it returned a true this time. Then I tried:

System.out.println(str1==str5);//false
System.out.println(str2==str5);//true

Also System.out.println("str"+"ing"=="string");//true

Aren't the supposed to come from the String pool? Could someone help explain this a bit?

Upvotes: 2

Views: 167

Answers (3)

irfan
irfan

Reputation: 896

The comparison works as follows:

String str1 = "str";`   //"str" is created in SCP and str1 is a reference to that    
String str2 = "string";` //"string" is created in SCP and str2 is a reference   
String str3 = "ing";`  //"ing" is created in SCP and str3 is a reference    
String str4 = str1 + str3;//"string" will be created on Heap and str4 is a reference (this is because if any string created at runntime will always be created on Heap) (here SCP already has this "string" so no change) make a note      that str4 is pointing to Heap string Object and not SCP   

str1 = str4; `// str1 and str4 will start pointing to same String Object on Heap    
String str5 = "string";`  // SCP already has this and str2 pointing to that so now onwards str5 will also point to it   

based on above    
1. str1 and str4 -- > are pointing to "string" object on heap    
2. str2 and str5 -- > are pointing to "string" object in scp  
3. str3 -- > is pointing to "ing" in scp   

and finally the corresponding output can be traced based on above lines:

System.out.println(str1==str2);`//false   
System.out.println(str1.intern()==str2.intern());`//true   
System.out.println(str1==str5);`//false   
System.out.println(str2==str5);`//true   
System.out.println("str"+"ing"=="string");`//true as "str"+"ing" will be replaced by "string" at compile time only (constant)

Upvotes: 0

5gon12eder
5gon12eder

Reputation: 25419

Only string literals and constant expressions are guaranteed to be pooled. Since str1 + str2 is not a literal, it's up to the JVM whether or not the result will be interned. You can force it via calling intern() as you have already found out.

This is defined in § 3.10.5 of the Java Language Specification:

A string literal is a reference to an instance of class String (§4.3.1, §4.3.3).

Moreover, a string literal always refers to the same instance of class String. This is because 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.

Your second example, "str" + "ing", is a constant expression so it is guaranteed to be interned.

Also see the JavaDoc for String.intern.

This is an attempt to explain what is going on. Well-written code should probably never rely on this but always use the equals method. Any reasonable JRE will have a check like

if (this == other)
  return true;

very close to the top of String.equals so performance wise, it shouldn't matter.

Upvotes: 6

Uhla
Uhla

Reputation: 368

Always use equals method for comparing strings. The trouble about interning is that each version of JDK does it a bit differently, so I wouldn't have counted on that unless you want to call intern every time on the string.

Upvotes: 0

Related Questions