java中的string intern、string concatenation和string常量池示例

yruzcnhs  于 2021-07-07  发布在  Java
关注(0)|答案(1)|浏览(397)
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)
有人能给我详细解释一下吗?

vkc1a9a2

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 都引用同一对象。
如果代码的顺序发生了变化,结果就不一样了,这就证明了:

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

相关问题