java字符串连接和实习

问题1

String a1 = "I Love" + " Java"; String a2 = "I Love " + "Java"; System.out.println( a1 == a2 ); // true String b1 = "I Love"; b1 += " Java"; String b2 = "I Love "; b2 += "Java"; System.out.println( b1 == b2 ); // false 

在第一种情况下,我理解它是两个字符串文字的串联,因此结果“I Love Java”将被实现,结果为真。 但是,我不确定第二种情况。

问题2

 String a1 = "I Love" + " Java"; // line 1 String a2 = "I Love " + "Java"; // line 2 String b1 = "I Love"; b1 += " Java"; String b2 = "I Love "; b2 += "Java"; String b3 = b1.intern(); System.out.println( b1 == b3 ); // false 

以上返回false,但如果我注释掉第1行和第2行,则返回true。 这是为什么?

问题的第一部分很简单:Java编译器将多个字符串文字的串联视为单个字符串文字,即

 "I Love" + " Java" 

 "I Love Java" 

是两个相同的字符串文字,它们得到适当的实习。

相同的实习行为不适用于+=对字符串的操作,因此b1b2实际上是在运行时构造的。

第二部分比较棘手。 回想一下b1.intern()可能返回b1或其他一些与它相等的String对象。 当你保持a1a2 ,你从b1.intern()的调用中得到a1 。 当您注释掉a1a2 ,没有要返回的现有副本,因此b1.intern()会返回b1本身。

来自intern()docs

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

并从JLS 3.10.5

  • 由常量表达式计算的字符串(第15.28节)在编译时计算,然后将其视为文字。
    • 在运行时通过串联计算的字符串是新创建的,因此是不同的。

你的字符串b1实际上没有实习。 因此差异。

问题1的答案:

您不能将两个String与==进行比较。 ==比较两种原始数据类型(int,long,float,double和boolean)或对象引用 。 这意味着如果引用变量(a1,a2,b1,b2)没有相同的引用(意味着它们不指向内存中的同一个对象),则它们不相等(与==比较)。

如果要与b1.equals(b2)进行比较,则表达式将为true,因为对象的数据是相同的。

在第一种情况下,Java足够聪明,可以在为它们分配一些内存(甚至在编译之前)之前连接字符串,这意味着两个字符串都存储在同一个地址中。 因此,变量a1和a2引用相同的对象并且相等( == )。

在第二种情况下,首先为变量分配不同的值(与第一种情况不同)。 这意味着他们在内存中获得了一个单独的地址。 即使您更改了值以使它们相同,地址也不会更改,并且与==的比较计算结果为false。 这在运行时发生。

至于问题2:@dasblinkenlight已经给出了一个很好的答案。