在JDK8和JDK9下,以下代码具有不同的结果。
public static void main(String[] args) {
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
String s3 = new String("1") + new String("1");
//String s3 = "1" + "1";
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
System.out.println(s3.equals(s4));
}
在JDK8(“ 1.8.0_172”版本)下,代码返回:
false
true
true
但在JDK9(“ 9.0.1”版本)下,代码返回:
false
false
true
我检查了两个JDK版本,它们是正确的。为什么代码的结果不同?我的程序有什么问题吗?
答案 0 :(得分:6)
结果取决于在调用s3.intern()
之前字符串池中是否已经有字符串“ 11”。
如果不是,s3.intern()
会将s3
添加到池中并返回s3
。在那种情况下,s4
也将被指定为“ 11”的规范表示形式,因为它是用String文字初始化的。因此s3==s4
将是true
。
如果是,则s3.intern()
将返回规范表示形式“ 11”,它与s3
实例不同。因此s3==s4
将是false
。
我没有用于测试代码的JDK9版本,但是如果得到的是输出,则表明在main
之前执行的JDK9源代码中的某处出现了“ 11 “ String
文字,它将String
添加到池中。
在JDK8中不是这种情况。
在两种情况下,使用“ 1” String
进行的测试都会得到false
,因为当您将String
“ 1”传递给{{1}时,会将其添加到池中} String
中的构造函数。因此,new String("1")
不会将s.intern()
引用的String
添加到池中,并且s
是与String s2 = "1";
不同的实例。
尝试了解此行为时,s
的Javadoc很方便:
字符串java.lang.String.intern()
返回字符串对象的规范表示。
最初为空的字符串池由String类私有维护。
调用intern方法时,如果池已经包含等于equals(Object)方法确定的此String对象的字符串,则返回池中的字符串。否则,将此String对象添加到池中,并返回对此String对象的引用。
...
所有文字字符串和字符串值常量表达式均已插入。
答案 1 :(得分:0)
伊兰的答案很接近。正如他所确定的,关键问题是何时字符串常量被插入。
根据我的权威,最近的一些JVM懒惰地进行String文字的中间化,并且它发生在第一次使用该文字之前。告诉这个人的人说这是/是新的行为。
因此,实际的解释似乎是Java 9是在引入这种新的“懒惰”行为时开始的,这解释了OP观察到的Java 8与Java 9之间的区别。
(我将尝试查看OpenJDK源代码中发生的情况...。)