java中的字符串实习生、字符串连接和字符串常量池示例

java中的字符串实习生、字符串连接和字符串常量池示例,java,string,string-concatenation,string-interning,string-pool,Java,String,String Concatenation,String Interning,String Pool,为什么s1和s4在堆中引用相同的对象? 为什么s1和s3在堆中引用相同的对象? 当我交换第2行和第3行时,o/p符合我的预期(o/p:false,false,false,true) 有人能详细解释一下吗?因为源文件中有“HelloWorld”,所以生成的.class文件包含该字符串常量,当类定义加载到JVM中时,字符串常量被添加到字符串常量池(SCP)中 这意味着我们希望s2、s3和s4都引用SCP中的字符串 不知道为什么“Hello”。concat(“World”)最终引用了SCP实例,尽管它

为什么s1和s4在堆中引用相同的对象? 为什么s1和s3在堆中引用相同的对象? 当我交换第2行和第3行时,o/p符合我的预期(o/p:false,false,false,true)

有人能详细解释一下吗?

因为源文件中有
“HelloWorld”
,所以生成的
.class
文件包含该字符串常量,当类定义加载到JVM中时,字符串常量被添加到字符串常量池(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()
    结果:
    s2=s1

  • 字符串常量“HelloWorld”由JVM解析,由于它已经在SCP中,因此返回SCP实例。
    结果:
    s3=s1

  • s3.intern()
    结果:
    s4=s3=s1

  • 结果如图所示:
    s1
    s2
    s3
    s4
    都引用同一对象

    如果代码的顺序发生变化,则结果不同,从而导致以下情况:

    String s1=“HelloWorld”;
    字符串s2=s1.intern();
    字符串s3=“Hello”.concat(“世界”);
    字符串s4=s1.intern();
    System.out.println(s1==s2);//真的
    System.out.println(s1==s3);//假的
    System.out.println(s1==s4);//真的
    
  • 字符串常量
    “HelloWorld”
    已解析并添加到SCP<代码>s1
    被分配给SCP实例

  • s1.intern()
    结果:
    s2=s1

  • concat()
    在堆中创建
    “HelloWorld”
    的新实例,并将其分配给
    s3

    结果:
    s3!=s1

  • s3.intern()
    结果:
    s4=s1


  • (s1==s4);//预期为假。但这是真的
    让我问一个反问题:为什么你期望这里出现
    false
    ?看看这里,也许它可以帮助你:字符串池的主要目的是让我们重用有机会在代码执行中重新出现的字符串。例如,当(…){System.out.println(“Name:”;…}
    时,则不应在每次迭代中创建字符串
    “Name:”
    。相反,它应该被缓存和重用。因此,当您编写类似于
    String str=“foo”
    Java将首先尝试在池中查找
    foo
    。如果找到它,它将分配给
    str
    对缓存的
    “foo”
    的引用。如果找不到,它将把它放在池中
    它试图在字符串池中查找
    HelloWorld
    ,既然这样的字符串存在(放在第2行),它就会重用它。@narendra但是为什么您希望
    false
    存在呢?第2行检查字符串池是否包含
    HelloWorld
    ,因此它将
    s1
    放在那里。第4行还检查字符串池是否包含
    HelloWorld
    ,因为它会返回它(这是前面第2行中放置的字符串,也是在第1行创建的字符串)。结果如图所示:s1、s2、s3和s4都引用相同的对象。您是说所有这些s1、s2、s3和s4都指向SCP或堆内存中的对象。若你们说所有的都指向堆内存,那个么当我清楚地声明了字符串s3=“HelloWorld”时,s3怎么能引用堆呢;如果你说所有人都指向SCP,那么当我清楚地声明了字符串s1=“Hello”.concat(“World”)时,s1怎么能引用SCP@narendra为什么您认为SCP中的
    字符串
    对象本身并不存储在堆中?SCP可以实现为一个简单的
    映射
    ,它也在堆中,这意味着整个SCP都在堆中。我唯一关心的是当我声明字符串s3=“HelloWorld”时,我相信这是在SCP中。但它证实,在某些情况下,它不在SCP中。谢谢你的解释。
    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
       }
    }