Java字符串字面量池和字符串连接引起的混淆

5

大家好,当我写下面的代码时遇到了一个问题:


String hello = "Hello";
String str5 = "Hel" + "lo";
String str8 = "Hel";
String str9 = "lo";
String str10 = str8 + str9;
System.out.println("str10==hello?" + (str10 == hello)); 
System.out.println("str5==hello?" + (str5 == hello));
System.out.println("str10==str5?" + (str10 == str5));

然后我运行我的代码,控制台打印出以下内容。
str10 == hello ? false
str5 == hello ? true
str10 == str5 ? false

这让我很困惑。为什么第二个打印是TRUE,而第一个打印是FALSE?在我对字符串字面值池的理解中,当定义一个字符串时,JVM会检查池中是否包含该字符串,如果没有,则将字符串放入池中。
在我的代码中,变量hello存在于字符串池中,“Helo”和“lo”也在池中,我的问题是:

  1. 连接“Helo”和“lo”的结果是否存在于池中。
  2. 关于str5和str10s的定义有什么区别,为什么它们不是“==”? str5和str10是否指向字符串池中不同的“Hello”?(“==”似乎意味着引用是相同的对象)

我的jdk版本:1.6.0_29
我的IDE:Intellij Idea 11.2

有人可以指出吗?非常感谢

4个回答

7
它的行为符合预期。在JLS的两个部分中进行了讨论。 JLS #3.10.5
常量表达式(§15.28)的值是字符串,并通过String.intern方法“interned”,以共享唯一实例。 JLS #15.28列出了常量表达式的定义。特别地,字符串文字是常量表达式(“Hel”和“lo”)。但对于变量被视为常量,必须使用final关键字。
在您的情况下,如果稍微更改代码以使str8和str9成为常量,则会三次获得true。
final String str8 = "Hel";
final String str9 = "lo";

1
String hello = "Hello";       // at compile time string is known so in String Constant Pool

String str5 = "Hel" + "lo";   // at compile time string is known so in String Constant Pool same object as in variable hello

String str8 = "Hel";          // at compile time string is known so in String Constant Pool

String str9 = "lo";           // at compile time string is known so in String Constant Pool

String str10 = str8 + str9;   // at runtime don't know values of str8 and str9 so in String Constant Pool new object different from variable hello

str10 == hello ? false        // as str10 has new object and not the same as in hello

str5 == hello ? true          // both were created at compile time so compiler know what's the result in str5 and referenced the same object to str5 as in hello

str10 == str5 ? false         // str10 is a different object, hello and str5 are referenced same object as created at compile time.

0
代码需要考虑以下几点:
String hello = "Hello";

这里的“Hello”是分配给引用hello的字面量,因此该字面量具有自己的哈希码。

String str5 = "Hel" + "lo";

在这里,“Hel” + “lo”是两个字面量组合并分配给引用hello,因此新字面量与第一个字面量相同,因此哈希码也相同。

String str8 = "Hel";
String str9 = "lo";

这里的str8 + str9是两个引用,它们组合并指向一个新的引用hello,因此新字面量有自己的哈希码

String str10 = str8 + str9;
System.out.println("str10==hello?" + (str10 == hello)); 
System.out.println("str5==hello?" + (str5 == hello));
System.out.println("str10==str5?" + (str10 == str5));

当您使用 == 时,它会根据哈希码和值进行匹配。因此导致不匹配。

尝试使用

string_1.equals(string_2)

使用

=

代替

==

string_1 = string_2

这样你就能得到值匹配,从而全部为真。

请参考下面的答案(来自Java 中 == 与 equals() 的区别是什么?):

equals() 方法比较堆上 String 实例内部的“值”,而不管两个对象引用是否指向同一个 String 实例。如果任何两个类型为 String 的对象引用都引用同一个 String 实例,那就太好了!如果这两个对象引用引用两个不同的 String 实例... 那也没关系。每个 String 实例内部的“值”(即字符数组的内容)被比较。

另一方面,“==”运算符比较两个对象引用的值,以查看它们是否引用同一个String实例。如果两个对象引用的值都“指向”同一个String实例,则布尔表达式的结果将为“true”...显然。如果另一方面,两个对象引用的值“指向”不同的String实例(即使两个String实例具有相同的“值”,即每个String实例的字符数组内容相同),则布尔表达式的结果将为“false”。

1
抱歉,我不理解“使用==匹配哈希码和值”的含义。<br>我打印出了str5、str8、str9、str10的每个哈希码,它们分别是hello.hash->69609650;str8.hash->72431;str9.hash->3459;str10.hash->69609650;str5.hash->69609650;正如我们所看到的,str5和str10的哈希码完全相同,但是str5 == str10返回false。 - fuye
谢谢您花时间编写这篇文章。它解决了我对“==”和“equals”的困惑。非常感激。 - fuye

-1
如果你要比较两个字符串,请使用 string.equals 而不是 string1 == string2 试一下:
System.out.println("str10==hello?" + (str10.equals(hello));

是的,正如我们在String equals源代码中所看到的,首先检查(if (this == anObject) {return true;}),然后判断它是否是String实例,如果是,则比较两个字符串对象的内容。 - fuye

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