String Constant Pool



正如在这些Stackoverflow问题中所解释的:问题1 &我理解"字符串字面值"在以下情况下被拘禁:

String s = "abc"; 

并且JVM将创建一个新的String对象,而不是使用字符串池中的现有对象:

String s = new String("abc");

然而,读了下面两个类似的陈述后,我有一个疑问。

  • 摘自SCJP准备书:

当编译器遇到String字面值时,它检查池中是否已经存在相同的String。如果找到匹配项,则对新字面值的引用将定向到现有的String,并且不会创建新的String字面值对象。

    从JavaRanch
  • :

在这种情况下,由于关键字"new",我们实际上以略有不同的行为结束。在这种情况下,对String字面值的引用仍然放在常量表(String Literal Pool)中,但是,当涉及关键字"new"时,JVM必须在运行时创建一个新的String对象,而不是使用常量表中的对象。

因此,如果我们在非池内存中也放置一个引用在池内存中,当我们使用"new"并基于上面的定义创建对象时。当我们这样做时,JVM不应该也返回相同的引用吗?:

String one = new String("test");
String two = "test";
System.out.println(one.equals(two)); // true
System.out.println(one == two);      // false

因为当声明字符串文字String three = "test";时,它将已经存在于池中?因此应该返回相同的引用并打印为真吗?或者前面的语句是否意味着它们将被放入池内存中,但在使用new操作符时只是被跳过?

也许这将有助于你的理解:

String literal = "test";
String one = new String(literal);
String two = "test";
System.out.println(literal == two); //true
System.out.println(one == two); //false

在你发布的例子中:

String one = new String("test");
String two = "test";

传递给构造函数String(String)的引用与引用two由于实习而具有相同的值。然而,字符串本身(由这两个引用引用)用于构造一个赋值给引用onenew对象。

在这个例子中,恰好有两个用值"test"创建的String:一个保存在常量池中,当你在表达式中使用文字"test"时引用它,另一个由"new"操作符创建并分配给引用one

编辑

也许你对这句话感到困惑:

当编译器遇到String字面值时,它检查池中是否已经存在相同的String。

注意,这可以更清楚地表述为:

当编译器遇到String字面值时,它检查池中是否已经存在一个相同的String

字符串只有在被显式存储或类使用文字时才会被放入池中。因此,如果您有,例如,这个场景:

String te = "te";
String st = "st";
String test = new String(te) + new String(st);

则当String存在且值为test时,所述字符串将不存在池中,因为文字"test"从未出现过。

    //Creates a new object even if one exists in the pool
    String s1 = new String("Tendulkar");
    // makes a new object string and then the reference is available to the pool
    String s2 = s1.intern();
    //this object is not created but references the address present in the pool
    String s3 = "Tendulkar";
    System.out.print(s1==s2); // results in false
    System.out.print(s2==s3); //very very true !!!

你的问题:

因此,如果我们同时在非池内存和池内存中放置一个引用,当我们根据上面的定义使用new创建对象时。当我们这样做时,JVM不也应该返回相同的引用吗?:

Ans:当您使用new关键字创建新的字符串对象时,生成的地址将是一个堆地址,而不是字符串常量池地址。两个地址是不同的

问题:

String one = new String("test");
String two = "test";
System.out.println(one.equals(two)); // true
System.out.println(one == two);      // false

前面的语句是否意味着它们将被放入池内存中,但在使用new操作符时只是被跳过?

答案:是的,你的假设是正确的。当程序员使用new关键字时,JVM将简单地忽略关于字符串常量池,并在堆中创建一个新的副本。因此两个地址不相同。

"abc"将对象放入常量池,在编译/类加载时,new String()创建一个新对象,在执行时。所以new String("abc")都做了,但是在不同的阶段。

字符串字面值的创建

  1. 每次创建字符串字面值时,JVM都会进行检查

  2. 如果该字符串在池中已经存在,则引用

  3. 如果字符串池中不存在,则创建一个新字符串实例被创建并放置在

  4. 池中

,

    String s1 = "Welcome";
    String s2 = "Welcome"; //will not create new instance

String Literal &字符串对象

    String str1 = "Hello World!!";
    String str2 = "Hello World!!";
    System.out.println(str1 == str2);// true

当String字面值str2被创建时,该字符串将被没有重新创建"Hello World"。相反,它是str1字符串被重用,因为它已经存在于字符串中常量池。

因为str1和str2都指向同一个

    String str3 = new String("Hello World!!");
    String str4 = new String("Hello World!!");
    System.out.println(str3 == str4); // false

在本例中,创建了新的String对象分别由str3和str4引用。因此,str3== str4为false。字符串在池中,str1 == str2为真

最新更新