【问题标题】:Java String literal pool and string objectJava 字符串字面量池和字符串对象
【发布时间】:2011-11-08 04:44:51
【问题描述】:

我知道 JVM 维护一个字符串文字池以提高性能并维护 JVM 内存,并了解到字符串文字是在字符串池中维护的。但是我想澄清一些与在堆上创建的字符串池和字符串对象有关的事情。

如果我的解释有误,请纠正我。

String s = "abc";

如果上面的行被执行,如果字符串池中不存在“abc”字符串字面量,它就会被添加到字符串池中。并且在堆上创建字符串对象,并且引用 s 将指向池中的文字。

问题:

  1. 这段代码每次执行时都会在堆上创建字符串对象吗?
  2. 字符串文字池是只维护字符串文字还是也维护字符串对象?
  3. JVM 何时决定需要将字符串文字添加到字符串池中?它是在编译时还是运行时决定的?

如果字符串对象指向池中的字符串文字,我不确定它是在哪里创建的。

谢谢。

【问题讨论】:

    标签: java string


    【解决方案1】:

    没有“文字池”。内部字符串只是普通的堆对象。它们可能最终会出现在 PermGen 中,但即便如此,它们最终也可能会被垃圾回收。

    类文件有一个常量池,其中包含类中使用的字符串字面量。加载类时,会根据该数据创建 String 对象,这可能与 String#intern 所做的非常相似。

    这段代码每次执行时都会在堆上创建字符串对象吗?

    没有。将有一个 String 对象被重用。它是在加载类时创建的。

    字符串文字池是只维护字符串文字还是也维护字符串对象?

    您也可以实习字符串。我认为他们的待遇或多或少是一样的。

    JVM 什么时候决定需要将字符串文字添加到字符串池中?它在编译时还是运行时决定?

    文字总是“合并”的。其他字符串需要调用“实习生”。所以在某种程度上,决定是在编译时做出的。

    【讨论】:

    • 如果被实习的字符串留在 PernGen 中,那么使用“new”关键字创建的字符串对象呢?是年轻一代创造的吗?
    • 所有新对象都是在年轻代中创建的。如果它们存活的时间足够长,它们就会迁移到其他地方。
    • “当类被加载时,String 对象会从该数据中创建出来,这可能与 String#intern 所做的非常相似。” 不只是相似: “...字符串字面量 - 或者更一般地说,作为常量表达式值的字符串(第 15.28 节) - 是“内部”的,以便使用 String.intern 方法共享唯一实例。” @987654321 @
    【解决方案2】:

    引用String.intern()的文档(强调我的

    所有文字字符串和字符串值常量表达式都是 实习。字符串字面量在 Java 语言的 §3.10.5 中定义 规格


    最初为空的字符串池由 类字符串。

    调用intern方法时,如果池中已经包含一个 字符串等于由 equals(Object) 确定的此 String 对象 方法,然后从池中返回字符串。否则,这 将字符串对象添加到池中并引用此字符串 对象被返回。


    因此,

    这段代码是否每次都在堆上创建字符串对象 执行了吗?

    只为每个唯一的实习字符串创建一个对象。所有引用共享这个不可变对象。

    字符串文字池是只维护字符串文字还是也维护字符串对象?

    没有“文字对象”。转换后的文字字符串表达式存储为常规 String 对象。此外,池包含所有内部字符串对象。隐式(通过使用字符串文字表达式)和显式(通过在 String 对象上调用 .intern())。

    JVM 什么时候决定需要在字符串中添加字符串字面量 水池?它在编译时还是运行时决定?

    我不确定。

    【讨论】:

    • JVM 决定。编译器会。在编译时。
    【解决方案3】:

    我认为你缺少一些基本的东西:实习字符串池 only 包含 String 对象。字面量不是某种特殊的对象。在运行时,它们只是另一个 String 对象。

    另外,您可以使用String.intern() 实习任何您想要的字符串;它不必源自文字。

    所以关于你的问题:

    1. 不,加载类时会分配一个String对象。
    2. 它不维护 任何 字面量,而是保留了 String 对象。通常,这些来自文字,但实际上它可以是任何编译时常量表达式(String constant = "abc" + "def" 会在运行时产生一个字符串对象“abcdef”)。
    3. 它们被编译到类文件中。所以它们是在编译时决定的,但显然对象本身是在运行时创建的。

    【讨论】:

    • “文字不是某种特殊的对象;在运行时它们只是另一个字符串对象。” 文字根本不是对象;它们是在源代码中编写对象(在这种情况下)的一种方式。文字的概念是源代码概念。文字的 resultString 对象。 (你稍后会很好地区分。)
    【解决方案4】:

    这段代码每次执行都会在堆上创建字符串对象吗?

    不。一旦在文字池中创建。一遍又一遍地提到同样的事情。

    字符串文字池是只维护字符串文字还是也维护字符串对象?

    所有都是对象,但是通过赋值创建的对象被放入池中,而通过new 运算符创建的对象被放入堆中。

    JVM 什么时候决定需要将字符串字面量添加到字符串池中?它是在编译时还是运行时决定的?

    每当 JVM 遇到类似的表达式时

    String str="Hello"; (string literal) or
    String str="Hel" + "lo"; (string constant expression).
    

    并且结果字符串(在这种情况下为str)不是池,那么在所有这些情况下,它都会在池中添加新字符串。这当然发生在运行时。

    查看this 链接。

    【讨论】:

    • 没有。到 JVM 在执行代码(例如您的答案)时看到字符串文字时,文字已经被实习,由编译器和类加载器放置在那里。常量表达式在编译时计算。
    • 请提供任何可证明您观点的链接/文章/示例。
    猜你喜欢
    • 2010-12-26
    • 2014-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多