Here is a java snippet:
public class TestIntern {
public static void main(String[] argvs){
String s1 = new StringBuilder("ja").append("va").toString();
String s2 = new StringBuilder("go").append("lang").toString();
System.out.println(s1 == s1.intern());
System.out.println(s2 == s2.intern());
}
}
And It behave different according to different JDKs
in Oracle JDK 1.7 output is:
false
true
in OpenJDK 1.6 output is also:
false
true
but in Oracle JDK 1.6 output is:
false
false
as the JavaDoc for this String#intern
method indicates
* When the intern method is invoked, if the pool already contains a
* string equal to this <code>String</code> object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this <code>String</code> object is added to the
* pool and a reference to this <code>String</code> object is returned.
~~~~
And what does *this* here mean? the string object
in the heap or in the string pool? if it returns
object in the heap the out put should be:
true
true
otherwise should *always* be:
false
false
Am I right?
the output:
true
true
should be expected, but neither three JDKs produce this. and Why Oracle JDK1.6 gives:
false
false
as a result?
I think in OracleJDK 1.7 and openJDK 1.6 there must be some reserved string in the string pool, and what are they? is there a document specify all the reserved strings? Really confused.
The method intern() creates an exact copy of a String object in the heap memory and stores it in the String constant pool. Note that, if another String with the same contents exists in the String constant pool, then a new object won't be created and the new reference will point to the other String.
String Interning is a method of storing only one copy of each distinct String Value, which must be immutable. By applying String. intern() on a couple of strings will ensure that all strings having the same contents share the same memory.
The Java String intern() method returns a canonical representation of the string object. Here, string is an object of the String class.
When you assigned a literal to string variable it will automatically be interned. This means the string object will be added to the java string pool automatically. In contrast, when you create a string using new operator you have applied intern() method to add its copy to the java string pool.
Whether or not s1.intern()
returns s1
or some other String
object depends on what it finds in the interned strings pool. If there's already some other String
object in the pool, intern()
will return that other object; otherwise it will put the String
object referenced by s1
into the pool and return that same object.
The issue is not the that different Java versions behave differently, it is that the pools happened to contain different things when you ran your tests. I don't find it particularly surprising that the pools in Oracle JDK 1.7 and openJDK 1.6 happened to already contain the string "java"
but not the string "golang"
.
Finally, I think I figured out all the confusions in this issue, and should make a summary.
This is a complementarity answer with @Ted answer, in his Post.
He point out that it is what the program finds in the string pool that affect the result of s1 == s1.intern()
returns. It perfectly explained the behavior of Oracle JDK 1.7 and the OpenJDK, but not the weird behavior of Oracle JDK 1.6, which will always return false
,regardless of whatever s1
is.
I think why Oracle JDK 1.6 always return false
is because of this internal string pool was in the permanent generation but was transferred to heap in JDK 1.7. So in JDK 1.6 string object on the heap and in the permanent generation will never be the same object.
To Prove this, I write a java program and run it under Oracle JDK 1.6
import java.io.*;
public class TestIntern {
public static void main(String[] argvs){
String s1 = null; // string inputed
String s2 = null; // string retrieved by string.intern() in this loop
String s3 = null; // string retrieved by string.intern() in last loop
while (true){
System.out.println("Enter the string");
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in));
try {
s1 = br.readLine();
}catch (IOException ex){
System.out.println("IOException caught, just exit");
System.exit(1);
}
s3 = s2; //<- s3 is referring to the string obj
//which retrieved from pool by last exec of loop
s2 = s1.intern(); //<- s2 now referring to the string
//obj retrieved from the string pool
// is s1 == s2 ? // this loop
if (s1 == s2){
System.out.println("s1 == s2 they are same string obj");
}else{
System.out.println("s1 != s2 they are NOT same string obj");
}
// is s2 == s3 ? compared from this loop retrieved(s2)
// and last loop retrieved(s3)
if(s2 == s3){
System.out.println("s2 == s3 they are same string obj");
}else{
System.out.println("s2 != s3 they are NOT same string obj");
}
}
}
}
We run this infinite loop function twice to figure out whether s2 and s3 is the same when we
use the same string from stdin
as input.
Apparently, when we input aaa
twice to the loop, s2 and s3 referred to the same string:
-> ~/Downloads/jdk1.6.0_45/bin/java TestIntern
Enter the string
aaa
s1 != s2 they are NOT same string obj
s2 != s3 they are NOT same string obj
Enter the string
aaa
s1 != s2 they are NOT same string obj
s2 == s3 they are same string obj
Enter the string
This means, string.inter()
did add aaa
to the string pool and return the object, but rather than the string object in the heap which installed by br.readLine()
, this returned object is the one in the permanent generation. they are not the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With