9

I have the code like this:

String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1); //true

String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2); //false

String str3 = new StringBuilder("Str").append("ing").toString();
System.out.println(str3.intern() == str3); //true

I can understand why str1.intern() == str1 and str3.intern() == str3 are true, but I don't understand str2.intern() == str2. Why this is false?

My java version is: 1.8.0_73

Ivar
  • 6,138
  • 12
  • 49
  • 61
Timi
  • 892
  • 1
  • 8
  • 17
  • 7
    because `"java"` is obviously already in the constant pool, so `str2.intern()` just returns that reference, which is different from the new `str2` reference. – Tom Mar 17 '16 at 14:30
  • @Tom Why the "java" already in the constant pool? and why "String" is not? – Timi Mar 17 '16 at 14:59

2 Answers2

17

String.intern() returns a String in the string literal pool. However if the string already exists in the pool, it will return the existing String.

If you pick a new String, it should return the String you created, but if you use a String which happens to exist in the pool already you will get the existing String.

It is reasonable to assume that in this case "java" already exists in the pool so when you call intern() it returns a different object so == is false.

note: string.intern().equals(string) should always be true.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • But how does that answer the question? I mean, it does not explain the above behavior. – user2004685 Mar 17 '16 at 14:30
  • @user2004685 How doesn't it? – Tom Mar 17 '16 at 14:31
  • @user2004685 For strings `==` compares the reference not the contents. – Peter Lawrey Mar 17 '16 at 14:32
  • 3
    *It is reasonable to assume that in this case "java" already exists in the pool so when you call intern() it returns a different object so == is false.* Now this make sense to me. Thanks! – user2004685 Mar 17 '16 at 14:32
  • @PeterLawrey But I don't konw why the "java" already in and why "String" is not? – Timi Mar 17 '16 at 15:01
  • @李思聪 you would need to check all the code which is run before this. By the time your program starts, it creates around 10,000 Strings. – Peter Lawrey Mar 17 '16 at 15:10
  • @李思聪 That is different question (related but different from the one you asked). Simple answer is "because it wasn't placed there while starting JVM". If you want to see content of pool you could try using something like http://stackoverflow.com/questions/22094111/how-to-print-the-whole-string-pool. – Pshemo Mar 17 '16 at 15:12
  • 2
    @李思聪 At a guess, this class is used on startup to launch the program http://www.docjar.com/html/api/com/sun/tools/jdi/SunCommandLineLauncher.java.html and on line 125 there is the String literal `"java"` – Peter Lawrey Mar 17 '16 at 16:02
4

The constant String "java" already exists in the Java constant pool, but you can verify that by changing

String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern()==str2);

to

String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == "java");

which will get the same constant and output

true

Alternatively, you could add "计算机软件" and "String" to the constant pool like

String a = "计算机软件";
String b = "String";
String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);

String str3 = new StringBuilder("Str").append("ing").toString();
System.out.println(str3.intern() == str3);

Then you would get (consistent with your observations)

false
false
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249