Java字符串拼接和内部化

7

问题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"将被池化,从而得到true的结果。然而,我不确定第二种情况。
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。为什么会这样?

2
我们从不使用“==”运算符比较字符串,而是使用“.equals”方法。 - Joey Pinto
1
@JoeyPinto使用==来学习Java内部机制,发现了一些看起来相当奇怪但有合理解释的行为。 - Sergey Kalinichenko
2个回答

13

你的问题的第一部分很简单:Java编译器将多个字符串字面量的连接视为单个字符串字面量,即

"I Love" + " Java"

"I Love Java"

这是两个完全相同的字符串字面量,它们会被正确地内部化。

对于字符串上的+=操作不适用相同的内部化行为,所以实际上在运行时构造了b1b2

第二部分比较棘手。回想一下,b1.intern()可能会返回b1或与之等效的其他String对象。当你保留a1a2时,从调用b1.intern()中获得了a1。当你注释掉a1a2时,没有现有的副本可供返回,因此b1.intern()会直接返回b1本身。


3

来自 intern() 文档:

所有字面量字符串和字符串常量表达式都会被汇编。字符串字面量的定义在 Java™ 语言规范的第3.10.5节中。

并且来自 JLS 3.10.5

  • 通过常量表达式(§15.28)计算出的字符串会在编译时计算,然后被当作字面量一样对待。
    • 通过运行时拼接计算出的字符串是新创建的,因此不同于字面量字符串。

您的字符串 b1 实际上没有被汇编。因此会有差异。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接