![](/img/trans.png)
[英]Why does String.intern() return different results under JDK8 and JDK9?
[英]Why String.intern() behave differently in Oracle JDK 1.7?
這是一個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中,字符串池中必須有一些保留的字符串,它們是什么? 是否有文件指定所有保留字串? 真的很困惑。
s1.intern()
是否返回s1
或某個其他String
對象取決於它在受約束的字符串池中找到的內容。 如果池中已經有其他String
對象,則intern()
將返回該其他對象; 否則,它將s1
引用的String
對象放入池中並返回該對象。
問題不在於不同的Java版本的行為不同,而是運行測試時池恰好包含不同的東西。 我並不感到特別驚奇的是,Oracle JDK 1.7和openJDK 1.6中的池恰好已經包含字符串"java"
而不包含字符串"golang"
。
最后,我想我已經弄清了這個問題上的所有困惑,應該做一個總結。
這是他的帖子中與@Ted答案的互補答案。 他指出,程序在字符串池中找到的內容會影響s1 == s1.intern()
返回的結果。 它完美地解釋了Oracle JDK 1.7和OpenJDK的行為,但沒有解釋Oracle JDK 1.6的怪異行為,無論s1
是什么,該行為總是返回false
。
我認為Oracle JDK 1.6總是返回false
的原因是因為此內部字符串池位於永久代中,但已轉移到 JDK 1.7中的堆中 。 因此,在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");
}
}
}
}
我們使用此無限循環函數兩次,以找出當我們使用來自stdin
的相同字符串作為輸入時,s2和s3是否相同。
顯然,當我們在循環中兩次輸入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()
安裝的堆中的字符串對象,該返回的對象是永久代中的那個。 她們不一樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.