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在堆中引用同一个对象?当我交换第2行和第3行时,o/p满足我的期望(o/p:false,false,false,true)
有人能给我详细解释一下吗?
1条答案
按热度按时间vkc1a9a21#
自
"HelloWorld"
在源文件中,生成.class
文件包含该字符串常量,当类定义加载到jvm时,字符串常量被添加到字符串常量池(scp)中。这意味着我们会期望
s2
,s3
,和s4
全部引用scp中的字符串。不知道为什么
"Hello".concat("World")
最后引用了scp示例,尽管它很可能是在jvm中实现的优化,因为concat()
是一个众所周知的字符串方法,字符串是众所周知的内存消耗。相反,
"Hello" + "World"
还应该引用scp示例,因为java编译器可以将该常量表达式计算为"HelloWorld"
,如拆卸.class
字节码使用javap
.更新
看来我弄错了,字符串中的常量
.class
文件不会在类加载时添加到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
都引用同一对象。如果代码的顺序发生了变化,结果就不一样了,这就证明了:
字符串常量
"HelloWorld"
已解析并添加到scp。s1
已分配scp示例。s1.intern()
简单地返回s1
因为它已经在scp中了。结果:
s2 = s1
concat()
创建的新示例"HelloWorld"
在堆中,并将其分配给s3
.结果:
s3 != s1
s3.intern()
添加引用的字符串s1
提交给scp,以及s2
被赋予相同的参考值。结果:
s4 = s1