簡體   English   中英

為什么String.intern()在Oracle JDK 1.7中表現不同?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM