【问题标题】:Where is the String literal which was passed in the constructor, stored when we create a new String object当我们创建一个新的 String 对象时,在构造函数中传递的 String 字面量在哪里
【发布时间】:2015-07-16 10:13:15
【问题描述】:

我们在 Java 中编写

String S1 = "TestString";
String S2 = "TestString";

然后与if(S1==S2)比较,我们得到布尔结果为真。 相同的解释是字符串常量是在字符串池中创建的,因此它与 S1 和 S2 在这里引用的字符串常量相同。 另外,如果我们写类似

String S1 = new String("TestString");

String S2 = new String("TestString");

然后与if(S1==S2)进行比较,我们得到错误。 原因是 S1 和 S2 的引用不同,因为字符串字面量是在堆中创建的。

我的问题是,在构造函数中传递的字符串文字“TestString”在哪里创建? 它与字符串文字/常量相同吗?因此应该像案例 1 一样在池中创建? 如果是那么当我们在上面两个语句之后写类似的东西时

String S3 = "TestString";

这不应该创建一个新的字符串文字,比较 if(S1==S3) 应该给我真,但它给假。

所以我无法弄清楚这个字符串文字是在何时何地在构造函数中被创建的。

任何帮助将不胜感激。 谢谢

【问题讨论】:

  • == 和 str1.equals(str2) 适用于不同的运算符/方法

标签: java string jvm string-pool


【解决方案1】:

我的问题是,在构造函数中传递的字符串文字“TestString”在哪里创建?它与字符串文字/常量相同吗?因此应该像案例 1 一样在池中创建?

正确,传递给构造函数调用new String("TestString")的常量字符串存储在字符串池中,就像在语句String S1 = "TestString"中一样。

String S1 = new String("TestString");

String S2 = new String("TestString");

String S3 = "TestString";

在这种情况下,S1==S3 给出 false,因为 S3 指的是由用于 S1 的构造函数的参数创建的字符串文字,而 S1 是一个不同的字符串(因为它是使用构造函数创建的)。

【讨论】:

  • 如果您在调试器中打开代码并查看S1.valueS2.value,您将看到类似[C@NNN 的内容,其中NNN 是表示“TestString”的字符数组的哈希码.对于支持 S1 和 S2 共享相同数据的声明的 S1 和 S2,这些值将相等
  • @DavidSoroko, a) 这是一个实现细节 b) 这在版本之间发生了变化 c) openjdk 8 中有一个选项可能会在运行时导致这些变化
  • 好的,所以如果 S1 和 S3 共享相同的字符串文字/常量。如果String S1 = new String("TestString"); S1 有引用,即它存储实际存储常量“TestString”的位置的内存地址,S3 也是如此,因为(如上所述,它们共享相同的文字)。我仍然有一个问题,当我们比较 S1 和 S3 引用时,为什么它们不相等(它们必须持有相同的内存地址)?
  • 因为我们有:S1 -> value (char[10]@123)S3 -> value (char[10]@123) - S1 和 S2 都引用内存中相同的字符数组/位置。但是 S1 和 S2 本身占用不同的内存位置,因此S1 == S2 是错误的
  • @Navneet S1 确实 not 存储对 String 文字的引用。它存储对 包含 文字的 String 对象的引用。另一方面,S3 引用文字。因此S1 == S3 是假的。
【解决方案2】:

如果(S1==S2),我们得到错误。

那是因为你有三个不同的字符串,S1、S2 和字符串文字。 S1 和 S2 是 String 对象的副本,并且具有不同的引用。因此,它们都不是==

我的问题是,在构造函数中传递的字符串文字“TestString”在哪里创建?

它像所有其他对象一样在堆上创建(从 Java 6 开始) 它也被添加到 String intern() 池中,因此任何其他相同的 String 文字都是同一个对象。

它与字符串文字/常量相同吗?

所有具有相同内容的字符串字面量都是同一个对象。

字符串 S3 = "TestString";这不应该创建一个新的字符串文字

正确。字符串文字已经被创建。

比较 if(S1==S3) 应该是真的

我不知道为什么。 S1 是字符串文字的副本,而不是字符串文字本身。

但它给出了错误。

正如预期的那样。

所以我无法弄清楚这个字符串字面量是在何时何地在构造函数中被创建的。

在 Java 7 之前,字符串字面量是在加载类时创建的,而在 Java 7+ 中,它是在首次使用时创建的。

如果 S1 和 S3 共享相同的字符串字面量/常量

直到 Java 6,它们共享相同的底层 char[]。从 Java 7 开始,情况并非如此。 String 对象一直是并且将永远是不同的。

S1 具有引用,即它存储了实际存储常量“TestString”的位置的内存地址

S1 是一个副本,因此它存储了对字符串文字副本的引用。

我仍然有一个问题,当我们比较 S1 和 S3 引用时,为什么它们不相等(它们必须持有相同的内存地址)

他们有不同的地址,这就是==给出错误的原因。

S1 和 S2 都在堆栈上,它们包含它们从堆中引用的各个对象的地址值。所以 S1 和 S2 本身会占据不同的位置(地址)。

名义上S1S2 具有不同的位置并指向不同的位置。但是,当代码转换为机器代码以实际运行时,可以对其进行优化,使变量位于寄存器中,而不是在堆栈中,并且任何未使用的变量都将被丢弃。即,可能不存在任何对象。

【讨论】:

    猜你喜欢
    • 2018-11-11
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    相关资源
    最近更新 更多