为什么字符串池对字面量和变量的行为不同?

4
当我使用双引号和加号运算符将2个字符串连接起来,并与具有相同值的其他字符串文字进行比较时,结果为true。但是当我连接2个字符串变量并进行比较时,结果为false?为什么会这样?
据我所知,当我们使用(+)运算符连接字符串时,JVM返回一个新的StringBuilder(string...)实例.toString(),它在堆内存中创建一个新的String实例和一个字符串池中的引用。如果这是真的,那么为什么在一个场景中返回true,在另一个场景中返回false呢?
第一个场景:
    String string1 = "wel";
    String string2 = "come";
    string1 = string1 + string2; //welcome

    String string3 = "welcome";
    System.out.println(string3 == string1); // this returns false but have same hashcode

第二种情况:
    String string4 = "wel" + "come";
    String string5 = "wel" + "come";
    System.out.println(string4 == string5); // this returns true

有人能帮我吗?

2
如果您连接非“final”String变量,则会生成StringBuilder。如果您连接String字面值,即常量,则不会生成。 - Sotirios Delimanolis
1
始终使用equals()方法比较字符串,如string3.equals(string1); - user2511414
4
据我所知,当我们使用(+)运算符连接字符串时,JVM会返回一个新的StringBuilder(string...).toString(),从而在堆内存中创建一个新的String实例。但是,当您在源代码中拼接字符串文字,例如"wel" + "come"时,这种拼接是在编译时完成的,它与您编写"welcome"是相同的。这一点在[Suresh Atta的答案](https://dev59.com/EHjZa4cB1Zd3GeqPbTcl#19497248)中指出。 - Joshua Taylor
@user2511414:我在这里使用==来检查两个值是否引用了字符串池中的同一个实例,这是验证字符串池引用的唯一方法。目的是了解字符串池的工作原理。 - manoj bhide
更好的解释是,Strings字面量并不是在字符串池中被合并,而是String常量。这包括编译器通过常量折叠过程创建的常量:http://ideone.com/ZxmLzN - millimoose
2个回答

4
请跟随注释。
 string1 = string1 + string2; //StringBuilder(string...).toString() which creates a new instance in heap..

 String string3 = "welcome"; // It is not in heap. 

所以 string3 == string1false

  String string4 = "wel" + "come"; //Evaluated at compile time

  String string5 = "wel" + "come"; //Evaluated at compile time and reffering to previous literal

所以,string4 == string5true

1
根据我的了解,当我们使用 (+) 运算符连接字符串时,JVM 返回 new StringBuilder(string...).toString(),这会在堆内存中创建一个新的 String 实例。
正确,除非两个操作数都是字面量,此时编译时将创建一个单个字符串常量并进行池化。
错误。字符串池中只有字符串常量和 String.intern() 的返回值。
不是这样的。
因为你的前提是错误的。

“在编译时创建单个文字是不准确的,因为文字是实际的语法特征 - 源代码中的表达式,如123"abc"。在编译时,会创建常量池中的条目 - 编译器不会生成源代码,因此不会创建文字。我也不会说创建了一个常量,因为它是变量的质量,而不是值的质量,值将是不可变的 - 无论它们是否是文字。” - millimoose
1
@millimoose 我同意关于“字符串字面量”的观点,而且在你发表评论几分钟前,我已经修复了它。但是我不同意“常量”的说法。这就是为什么它被称为“常量池”的原因,用于存储常量。有很多常量并不是变量,例如字符串字面量。 :-| - user207421
我承认在父级部分可能是在语义上纠结,我只是为了完整表达我的想法而添加了那部分,而不是指出错误。 - millimoose

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