这是一个java片段:
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());
}
}
根据不同的JDK,它的行为不同
Oracle JDK 1.7输出中的是:
false
true
OpenJDK 1.6输出中的也是:
false
true
但在Oracle JDK 1.6输出中是:
false
false
因为此String#intern
方法的JavaDoc表示
* 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?
输出:
true
true
应该是预期的,但是三个JDK都不会产生这个。以及为什么Oracle JDK1.6给出了:
false
false
结果呢?
我认为在OracleJDK 1.7和openJDK 1.6中,字符串池中必须有一些保留的字符串,它们是什么?是否有文档指定所有保留的字符串? 真的很困惑。
答案 0 :(得分:5)
s1.intern()
是否返回s1
或其他String
对象取决于它在实习字符串池中找到的内容。如果池中已经存在其他String
个对象,intern()
将返回该另一个对象;否则它会将String
引用的s1
对象放入池中并返回相同的对象。
问题不在于不同的Java版本表现不同,而是在运行测试时,池碰巧包含不同的内容。我发现Oracle JDK 1.7和openJDK 1.6中的池恰好已经包含字符串"java"
而不是字符串"golang"
,这一点并不特别令人惊讶。
答案 1 :(得分:0)
最后,我想我已经弄清了这个问题的所有混淆,应该做一个总结。
这是@Ted回答的补充答案,在他的帖子中。
他指出,这是程序在字符串池中找到的影响s1 == s1.intern()
返回结果的内容。它完美地解释了Oracle JDK 1.7和OpenJDK的行为,但不是Oracle JDK 1.6的奇怪行为,它始终返回false
,无论s1
是什么。
我认为Oracle JDK 1.6总是返回false
的原因是因为内部字符串池在永久代中,而在JDK 1.7中是was transferred to heap。所以在JDK 1.6中,堆上的字符串对象和永久代中的对象永远不会是同一个对象。
为了证明这一点,我编写了一个java程序并在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");
}
}
}
}
我们运行这个无限循环函数两次,以确定当我们s2和s3是否相同时
使用stdin
中的相同字符串作为输入。
显然,当我们向循环输入aaa
两次时,s2和s3引用相同的字符串:
-> ~/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
这意味着,string.inter()
确实将aaa
添加到字符串池并返回对象,而不是由br.readLine()
安装的堆中的字符串对象,此返回的对象是永久的一代。他们不一样。