28

正如这些 Stackoverflow 问题中所解释的:问题 1问题 2我理解“字符串文字”在以下情况下被实习

String s = "abc"; 

并且 JVM 将在以下情况下创建一个新的 String 对象,而不是使用来自 String Pool 的现有对象:

String s = new String("abc");

但是,在阅读了以下两个类似的陈述后,我有一个疑问。

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

在这种情况下,由于关键字“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";量时它已经存在于池中?因此应该返回相同的引用并打印 true?或者前面的语句是否意味着它们将被放入池内存中,但在使用new运算符时只是跳过?

4

5 回答 5

33

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

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但是,字符串本身(由这两个引用引用)用于构造分配给 reference 的对象one

在这个例子中,正好有两个String用值“test”创建:一个保存在常量池中,每当你"test"在表达式中使用文字时都会引用它,第二个是由“new”运算符创建并分配给参考one

编辑

也许你对这个说法感到困惑:

当编译器遇到字符串字面量时,它会检查池以查看是否已经存在相同的字符串。

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

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

字符串仅在显式实习或通过类使用文字时才放入池中。因此,例如,如果您有这种情况:

String te = "te";
String st = "st";

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

然后虽然 aString将与 value 一起存在test,但所述 String 将不会存在于池中,因为字面"test"量从未发生过。

于 2013-01-04T03:23:46.620 回答
8
    //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 !!!
于 2013-11-16T17:51:11.010 回答
2

"abc"在编译/类加载时将一个对象放入常量池,并在执行时new String()创建一个新对象。两者也是如此,但处于不同的阶段。new String("abc")

于 2013-01-04T09:12:48.093 回答
2

你的问题 :

因此,如果我们在使用“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 将简单地忽略字符串常量池,并在堆中创建一个新副本。因此,两个地址都不相同。

于 2013-12-10T07:06:53.683 回答
0

字符串文字的创建

  1. 每次创建字符串字面量时,JVM 首先检查字符串常量池

  2. 如果字符串已经存在于池中,则返回对池中实例的引用

  3. 如果池中不存在字符串,则创建一个新的字符串实例并将其放入池中

例子,

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

字符串文字和字符串对象

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

创建字符串字面量 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 为假。池中的字符串,str1 == str2 为真。

于 2019-12-05T03:12:01.457 回答