Java 为什么新字符串()和#x2B;new String()在JDK8下返回不同的结果

Java 为什么新字符串()和#x2B;new String()在JDK8下返回不同的结果,java,string,Java,String,以下代码在JDK8 1.8.0_171下具有不同的结果 @Test public void test2() { String s1 = new String("a") + new String("a"); s1.intern(); String s2 = "aa"; System.out.println(s1 == s2); //true } @Test public void test3() {

以下代码在JDK8 1.8.0_171下具有不同的结果

@Test
public void test2() {
    String s1 = new String("a") + new String("a");
    s1.intern();
    String s2 = "aa";
    System.out.println(s1 == s2); //true
}
@Test
public void test3() {
    String s1 = new String("1") + new String("1");
    s1.intern();
    String s2 = "11";
    System.out.println(s1 == s2); //false
}
唯一的区别是值:“a”而不是“1”,我得到的结果是不同的。这是为什么?

s1.intern()
仅将
s1
引用的
字符串添加到
字符串
池中,前提是该池中尚未包含与其相等的
字符串

诸如“aa”和“11”之类的字符串文本始终处于内部,因此它们将始终是
=
s1.intern()返回的实例

因此,
s1==s2
是否返回
true
取决于
字符串
所包含的
池在调用
s1.intern()
之前是否等于
s1

  • 如果是这样,
    s1.intern()
    ==s2
    不是
    ==s1
    ,因此
    System.out.println(s1==s2)
    将打印
    false
  • 如果没有,则
    s1.intern()==s1==s2
    ,因此
    System.out.println(s1==s2)
    将打印
    true

这可以在Java版本之间更改,因为不同版本的JDK类可能包含不同的
字符串
文本集,这些文本在执行代码之前会自动插入。

因为
=
操作符检查两个变量是否引用完全相同的对象。比如说

String s1 = new String("foo");
String s2 = s1;
System.out.println(s1 == s2); //true
如果您有两个单独的实例,并且希望根据它们的值比较字符串,那么应该使用
String::equals

String s1 = new String("foo");
String s2 = new String("foo");
System.out.println(s1.equals(s2)); //true
请退房

当涉及到
String:intern时,您必须在两个实例上调用它,以便比较它们,而不仅仅是其中一个<代码>字符串foo=“foo”
仍然隐式创建
字符串的新实例。Java中没有原语
string

String s1 = new String("foo");
String s2 = "foo";
System.out.println(s1.intern() == s2.intern());

这是为了给埃兰的伟大答案添加一个例证。以下假设
“aa”
在执行代码之前未被实习(隐式或非隐式):

s1
s3
都有相同的文本(
“aa”
),因此实际文本中的差异不会造成差异。对
.intern()
的第二次调用没有导致
s3
被放入池中(因为池中已经包含
“aa”
,这是
s1.intern()
的结果),解释了
=
s3
s2
之间返回false的原因

简而言之,这意味着在执行
test3()
方法之前,
“11”
已被实习


对于附加测试,移动
String s2=“aa”到代码的开头(两个比较都返回
false
,原因相同-尽管这可能取决于版本或实现)

我根本不依赖
=
进行字符串比较,也就是说,它们是否已被占用并不重要。因此,从实际的角度来看,这个问题可能是没有意义的。为了验证这一点:只需添加一个打印(或处理)字符串常量的
test0
“aa”
,就会使
test2
打印错误(只要
test0
test2
之前执行)。聪明的答案。花了几秒钟的时间来了解您所谈论的内容。JVM之间另一个明显的变化是,文本是在类加载时、类初始化时还是。。。第一次执行某个方法时,总是懒洋洋的。@ernest_k我还是不明白:(这很令人困惑,因为在
test2
中,输出会根据是否调用
intern
而变化。似乎
intern
会将
s1
重新分配给其他对象!如果是
s1=s1.intern();
,这两个测试都是正确的,但由于返回值被忽略(
intern
仅将字符串添加到字符串池中,但由于
aa
11
是文本,它们已经存在,因此
intern
实际上什么都不做),为什么
test2
仍然打印为true?@Sweeper:不,
intern
不能也不会更改
s1
是什么。但是当使用该方法首次插入字符串值时,调用
intern
的实际实例将成为该实习生池的成员。因此,与其
intern
更改
s1
的内容>也就是说,它改变了从实习生池初始化时,
s2
将变成什么:由
s1
实习的值,或者(如果您不调用
intern
)它变成了一个新的字符串实例,其值与放入intern池的值相同。这是基本情况信息。但它没有解释OP提供的两个测试为何会产生不同的输出,也没有解释调用
s1.intern()的原因
如果不将结果重新传回
s1
将更改测试的输出。
String s1 = new String("a") + new String("a");
s1.intern();
String s2 = "aa";
System.out.println(s1 == s2); //true

String s3 = new String("a") + new String("a"); //same text
s3.intern();
System.out.println(s3 == s2); //false