Java String文字池和字符串对象

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

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

String s = "abc"; 

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

问题:

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

如果它指向池中的字符串文字,我不确定创建字符串对象的确切位置。

谢谢。

没有“文字池”。 Interned Strings只是普通的堆对象。 它们最终可能会进入PermGen,但即便如此,它们最终也可能被垃圾收集。

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

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

不会。将有一个正在重用的String对象。 它已在加载类时创建。

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

你也可以实习字符串。 我认为他们的待遇大致相同。

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

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

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

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


最初为空的字符串池由String类私有维护。

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


从而,

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

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

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

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

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

我不确定。

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

另外,你可以使用String.intern()实习你想要的任何String; 它不一定来自文字。

关于你的问题:

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

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

不。 一旦在文字池中创建。 同样一次又一次地提到。

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

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

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

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

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

并且结果字符串(在本例中为str )不是池,然后在所有这些情况下,它在池中添加新字符串。 这个过程在运行时发生。

看看这个链接。