为什么这两个相似的代码片段会导致不同的结果?
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,混合模式)
答案 0 :(得分:3)
大概gg
是在String Pool发生的,尽管我不知道怎么回事,也许Junit在幕后做过一些事。字符串池,它被再次引用而不是再次实例化。这就是为什么使用true
运算符在代码的第二部分获得==
的原因。 对于某些字符串比较,应始终使用equals方法。
您了解intern()方法实际上在做什么吗?
可以使用String的intern()
方法将 String对象添加到该池中。对于任意两个字符串s和t,当且仅当s.intern() == t.intern()
为真时,true
为s.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"
相同的结果。