jdk8中的String#intern()

时间:2018-07-16 07:23:41

标签: java string junit

为什么这两个相似的代码片段会导致不同的结果?

public class Test {
    @org.junit.Test
    public void test1() {
        String s3 = "1" + new String("1");
        String s5 = s3.intern();
        System.out.println(s5 == s3);
    }

    @org.junit.Test
    public void test2() {
        String s3 = "g" + new String("g");
        String s5 = s3.intern();
        System.out.println(s5 == s3);
    }
}   

在jdk 1.8.0_144环境中尝试过,得到了以下答案(在jdk6中可能有所不同):

  

假    和    是

第一个代码段在Java8中应该为true。 但更令人困惑的是,如果我将代码移到main方法中,它将得到true。

public class TestWithoutJunit {
    public static void main(String[] args) {
        String s3 = "1" + new String("1");
        String s5 = s3.intern();
        System.out.println(s5 == s3);
    }
}

我认为这是对JUnit的优化,因此我检查字节码,jUnit内部的两个代码段和main函数保持完全相同。

顺便说一下,我的Java版本

  

java版本“ 1.8.0_144”   Java(TM)SE运行时环境(内部版本1.8.0_144-b01)   Java HotSpot(TM)64位服务器VM(内部版本25.144-b01,混合模式)

2 个答案:

答案 0 :(得分:3)

大概gg是在String Pool发生的,尽管我不知道怎么回事,也许Junit在幕后做过一些事。字符串池,它被再次引用而不是再次实例化。这就是为什么使用true运算符在代码的第二部分获得==的原因。 对于某些字符串比较,应始终使用equals方法。

您了解intern()方法实际上在做什么吗?

可以使用String的intern()方法将

String对象添加到该池中。对于任意两个字符串s和t,当且仅当s.intern() == t.intern()为真时,trues.equals(t)

所有文字字符串和字符串值常量表达式均已插入。

@Edit:OP说成是评论,

  

我检查了常量池,在此之前找不到"11"之类的东西   行:String s4 = "11";

至少在Java VM的HotSpot实现中,您无法从Java代码访问字符串池。这就是为什么您在11之前看不到String s4 = "11"

答案 1 :(得分:1)

就像其他人说的那样,您应该使用.equals来比较字符串,但是如果您想知道为什么在这种情况下却有不同的结果,那么:

默认情况下,每个字符串文字都会添加到字符串池中,并且由于"1"字符串已在不同类中用作文字,因此.intern返回不同的实例,对于"g"没有该文字的其他用法,因此您的变量是第一个添加到字符串池的变量-因此.intern在这种情况下不会更改任何内容-因为它返回的实例与您的实例相同。
"11""gg"字符串相同。
确切地说,在JDK 8上,sun.text.resources.FormatData似乎使用了它。 (两个字符串,"1""11"

如果您要添加其他带有"g"文字的类,而该类将在此类之前加载-您将获得与"1"相同的结果。