首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么String.intern()在OracleJDK1.7中的行为有所不同?

为什么String.intern()在OracleJDK1.7中的行为有所不同?
EN

Stack Overflow用户
提问于 2015-01-07 04:59:27
回答 2查看 371关注 0票数 5

下面是一个java片段:

代码语言:javascript
复制
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的输出是:

代码语言:javascript
复制
false
true

在OpenJDK 1.6中,输出也是:

代码语言:javascript
复制
false
true

但是在Oracle JDK 1.6中的输出是:

代码语言:javascript
复制
false
false

正如此JavaDoc方法的String#intern指示的那样

代码语言:javascript
复制
 * 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?

产出:

代码语言:javascript
复制
true
true

应该是预期的,但这两个JDK都不会产生这种情况。以及Oracle JDK1.6给出的原因:

代码语言:javascript
复制
false
false

结果?

我认为在OracleJDK 1.7和openJDK 1.6中,字符串池中一定有一些保留字符串,它们是什么?是否有指定所有保留字符串的文档?真的很困惑。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-07 05:03:09

s1.intern()是否返回s1或其他String对象取决于它在内部字符串池中找到了什么。如果池中已经有其他String对象,intern()将返回另一个对象;否则,它将将s1引用的String对象放入池中并返回相同的对象。

问题不是不同的Java版本的行为不同,而是池在运行测试时碰巧包含了不同的内容。我不觉得特别奇怪的是,OracleJDK1.7和openJDK 1.6中的池已经包含了字符串"java",而没有包含字符串"golang"

票数 5
EN

Stack Overflow用户

发布于 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下运行它

代码语言:javascript
复制
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引用相同的字符串:

代码语言:javascript
复制
-> ~/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对象不同,返回的对象是永久生成的对象。他们不一样。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27812666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档