String.intern()如何工作

时间:2014-09-27 14:27:50

标签: java string

package com.zhb.jvm;

/**
 * 
 * @author zhb
 *
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args){

        String str1 = "abc";
        System.out.println(str1.intern() == str1);    //true
        String str2 = new String("abcd");
        System.out.println(str2.intern() == str2);    //false

        String str3 =new StringBuilder("math").append("analyze").toString();
        System.out.println(str3.intern() == str3);    //true

        String str4 =new StringBuilder("computer").append("software").toString();
        System.out.println(str4.intern() == str4);    //true

        String str5 =new StringBuilder("jav").append("a").toString();
        System.out.println(str5.intern() == str5);    //false
    }

}

首先,我们可以知道intern()方法的定义。 intern的定义:当调用intern方法时,如果池已经包含等于equals(Object)方法确定的thisString对象的字符串,则返回池中的字符串。否则,将thisString对象添加到池中,并返回对此String对象的引用。

str1.intern == str1为true。这很容易理解。 str2.intern()== str2这个方法的定义也很容易理解。 但是为什么str3.intern()== str3是真的。事实上,我认为它的定义是错误的。 str5.intern()== str5与false相反。 我在终端上运行命令 java -version java版“1.7.0_40” Java(TM)SE运行时环境(版本1.7.0_40-b43) Java HotSpot(TM)64位服务器VM(内置24.0-b56,混合模式)

我想获得正确答案。非常感谢你!

4 个答案:

答案 0 :(得分:1)

  

为什么str3.intern()== str3为真

因为,正如你所说:

  

否则,将thisString对象添加到池中,并返回对此String对象的引用。

你就是这样。该池还不包含str3(即“mathanalyze”)。所以str3被添加到池中并返回。

对于str5,你是另一种情况:

  

如果池已经包含等于thisString对象的字符串(由equals(Object)方法确定),则返回池中的字符串

因此,当代码执行时,池已经包含字符串“java”,这并不奇怪,因为java是,例如,所有标准类的顶级包的名称,以及名称用于启动JVM的可执行文件。文本字符串“java”很可能用于引导应用程序并在执行main方法之前加载类的代码。

答案 1 :(得分:1)

我看到它的方式,我会说默认情况下字符串"java"在池中。实际上,当你在str3上调用intern()时,这个单词还没有在池中,所以它被添加并且返回的引用是str3(没有创建新对象),所以测试给出了true。相反,"java"已经在池中,因此它返回池中对象的引用,这与str5的引用不同。

请注意,您不仅会使用"java",还会使用所有单个字符来观察相同的行为。

答案 2 :(得分:0)

测试foo.intern() == foo是一种在foo被调用之前测量intern()是否已在池中的方法。因此str3.intern() == str3表示str3尚未在池中。就是这样。

在复制之前,运行时中某处可能存在一个常量字符串"java",这就是str5.intern() != str5的原因。

以下是通过grepping OpenJDK 8源代码找到的最明显的案例:

./com/sun/beans/decoder/DocumentHandler.java:        setElementHandler("java", JavaElementHandler.class); // NON-NLS: the element name
./com/sun/tools/example/debug/gui/JDBMenuBar.java:        JDBFileFilter filter = new JDBFileFilter("java", "Java source code");
./com/sun/tools/jdi/SunCommandLineLauncher.java:                "java",
./sun/launcher/LauncherHelper.java:                (progname == null) ? "java" : progname ));
./sun/rmi/server/Activation.java:                        File.separator + "bin" + File.separator + "java";
./sun/rmi/server/Activation.java:                    command[0] = "java";

答案 3 :(得分:0)

据我所知,可能有任何运行时字符串" java" ,这会导致这个问题。

    String str5 =new StringBuilder("jav").append("a").toString();
    System.out.println(str5.intern() == str5);    //false

以上两个语句仅为false,除了您希望与true一起传递的任何其他字符串。

符合Java规范的Intern()。

这将返回字符串对象的规范表示。最初为空的字符串池由String类私有维护。调用实习方法时,如果池已经包含等于此字符串对象的字符串(由equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回对此String对象的引用。因此,对于任何两个字符串s和t,当且仅当s.equals(t)为真时,s.intern()== t.intern()才为真。

所有文字字符串和字符串值常量表达式都是实体。字符串文字在The Java™Language Specification。的第3.10.5节中定义。

<强>返回: 与此字符串具有相同内容的字符串,但保证来自唯一字符串池。

希望它会对你有所帮助。