简体   繁体   中英

Why are the results of of str == str.intern() for these strings different?

public static void main(String[] args) {
    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);
    String str2 = new StringBuffer("ja").append("va").toString();
    System.out.println(str2.intern() == str2);
}

Results:

 true
 false   

First one prints true , and the second prints false . Why are the results different?

The difference in behavior is unrelated to the differences between StringBuilder and StringBuffer .

The javadoc of String#intern() states that it returns

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned . Otherwise, this String object is added to the pool and a reference to this String object is returned.

The String created from

String str2 = new StringBuffer("ja").append("va").toString();

is a brand new String that does not belong to the pool.

For

str2.intern() == str2

to return false , the intern() call must have returned a different reference value, ie. the String "java" was already in the pool .

In the first comparison, the String "计算机软件" was not in the string pool prior to the call to intern() . intern() therefore returned the same reference as the one stored in str2 . The reference equality str2 == str2 therefore returns true .

Because your assignments don't re-read from the intern pool and Java String (s) are immutable. Consider

String str1 = new StringBuilder("计算机").append("软件").toString();
String str1a = new String(str1); // <-- refers to a different String 
str1 = str1.intern();
str1a = str1a.intern();
System.out.println(str1a == str1);
String str2 = new StringBuffer("ja").append("va").toString();
String str2a = new String(str2); // <-- refers to a different String 
str2 = str2.intern();
str2a = str2a.intern();
System.out.println(str2a == str2);

The output is (as you might expect)

true
true

Lots of answer before mentioned about the pool and explained really clearly with the Oracle link docs.

I just would like to point out the way we can check when debugging code.

    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);//the str1.intern() returns the same memory address the str1
    String str2 = new StringBuffer("ja").append("va").toString();
    System.out.println(str2.intern() == str2);//the str2.intern() does not return the same memory address the str2

You can use any IDE and debug to check the actual address that the str1 and str1.intern()/str2 and str2.intern().

let me add something more interesting:

  1. the OpenJDk 8 is true,true;
  2. Oracle JDK 6 is true,true;

so I think the right answer is :

diffrent vendor's jvm or jvm versions may have diffrent implemention(the language specification don't force the how to)

In Oracle JDK 8(I guess u using): String “java” already in pool(loaded by java.lang.Version#laucher_name) and String pool only stores the refrence,not the object.

But in OpenJDK the laucher_name is "openJDK";In Oracle JDK 6 and below ,the string pool will copy the string object to itslef .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM