package com.lang;
class StringConcatDemo2
{
public static void main(String[] args)
{
String s1 = "Hello".concat("World"); // s1 to be created in heap.
String s2 = s1.intern(); //Line-2 //Since "HelloWorld" doesn't exist in String constant pool (SCP), s1 and s2 point the same.
String s3 = "HelloWorld"; //Line-3 s3 to be created in SCP.
String s4 = s1.intern(); //Since "HelloWorld" exists in SCP, s3 & s4 should refer to String in SCP.
System.out.println(s1 == s2); // true
System.out.println(s1 == s4); // Expected false. But it is true.
System.out.println(s1 == s3); // Expected false. But it is true.
System.out.println(s3 == s4); //true
}
} 为什么s1和s4在堆中引用相同的对象?为什么s1和s3在堆中引用相同的对象?当我交换Line-2和Line-3时,o/p符合我的预期(o/p: false,true)
有人能给我详细解释一下吗?
发布于 2020-12-02 07:32:04
由于JVM位于源文件中,因此生成的.class文件包含该字符串常量,并且在将类定义加载到"HelloWorld"中时,该字符串常量被添加到字符串常量池(SCP)。
这意味着我们期望s2、s3和s4都引用SCP中的字符串。
我不知道为什么"Hello".concat("World")最终会引用SCP实例,尽管这可能是在JVM中实现的优化,因为concat()是众所周知的字符串方法,而字符串是众所周知的占用内存的方法。
相反,"Hello" + "World"也应该引用SCP实例,因为Java编译器可以将该常量表达式求值为"HelloWorld",这在使用javap反汇编.class字节码时可以看到。
已更新
看起来我错了,.class文件中的字符串常量不是在装入类时添加到SCP中,而是在第一次使用字符串常量时添加到SCP中。
这意味着序列如下:
为
s1分配了字符串"HelloWorld",该字符串不在SCP中。s1.intern()将s1引用的字符串添加到SCP中,并为s2分配相同的引用值。结果:s2 = s1
"HelloWorld"由JVM解析,因为它已经在SCP中,所以会返回SCP实例。结果:s3 = s1
s3.intern()只返回s3,因为它已经在SCP中了。结果:s4 = s3 = s1
结果如下所示:s1、s2、s3和s4都引用了同一个对象。
如果代码的顺序改变了,结果就会不同,这会导致以下结果:
String s1 = "HelloWorld";
String s2 = s1.intern();
String s3 = "Hello".concat("World");
String s4 = s1.intern();
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // true解析
"HelloWorld"并添加到SCP中。将为s1分配SCP实例。s1.intern()只返回s1,因为它已经在SCP中了。结果:s2 = s1
concat()在堆中创建"HelloWorld"的新实例,并将其分配给s3。结果:s3 != s1
s3.intern()将s1引用的字符串添加到SCP中,并为s2分配相同的引用值。结果:s4 = s1
https://stackoverflow.com/questions/65099188
复制相似问题