下面是一个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());
}
}并且根据不同的JDKs表现出不同的行为。
在Oracle JDK中,1.7的输出是:
false
true在OpenJDK 1.6中,输出也是:
false
true但是在Oracle JDK 1.6中的输出是:
false
false正如此JavaDoc方法的String#intern指示的那样
* 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中,字符串池中一定有一些保留字符串,它们是什么?是否有指定所有保留字符串的文档?真的很困惑。
发布于 2015-01-07 05:03:09
s1.intern()是否返回s1或其他String对象取决于它在内部字符串池中找到了什么。如果池中已经有其他String对象,intern()将返回另一个对象;否则,它将将s1引用的String对象放入池中并返回相同的对象。
问题不是不同的Java版本的行为不同,而是池在运行测试时碰巧包含了不同的内容。我不觉得特别奇怪的是,OracleJDK1.7和openJDK 1.6中的池已经包含了字符串"java",而没有包含字符串"golang"。
发布于 2015-01-08 08:54:19
最后,我想我找出了这个问题的所有困惑,应该做一个总结。
这是一个互补的答案和@泰德回答,在他的帖子。他指出,影响s1 == s1.intern()返回结果的是程序在字符串池中发现的内容。它完美地解释了OracleJDK1.7和OpenJDK的行为,但没有解释OracleJDK1.6的奇怪行为,它总是返回false,而不管s1是什么。
我认为OracleJDK1.6总是返回false的原因是因为这个内部字符串池在永久代,而被转移到堆中在JDK1.7中。因此,在JDK1.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()安装的堆中的string对象不同,返回的对象是永久生成的对象。他们不一样。
https://stackoverflow.com/questions/27812666
复制相似问题