You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OCP 1Z0-815备考:+运算符非字符串操作数转字符串是否入池?

关于OCP 1Z0-815备考中字符串拼接的对象创建与回收疑问解答

嘿,针对你备考时遇到的这两个字符串拼接相关的疑问,我来给你拆解得明明白白:


一、循环拼接代码的对象计数与入池问题

先看这段代码:

String str = "hello"; 
for( int i = 0; i < 5; i++) { 
    str = str + i; 
}

书中说共创建11个String对象,咱们来算清楚这个数的由来:

  • 初始的"hello"是字符串池中的1个对象;
  • 循环5次,每次循环里的i会被转成对应的字符串("0"、"1"…"4"),这是5个临时String对象;
  • 每次str + i的拼接操作,会生成一个新的String对象("hello0"、"hello1"…"hello4"),这又是5个对象;
  • 加起来1+5+5=11,正好对应书中的结论。

至于你提到的JLS 15.8.1没明确非字符串操作数转成的String是否入池:这类由基本类型转换生成的字符串(比如Integer.toString(i)的结果),默认是不会进入字符串池的,只有字符串字面量、编译期常量拼接的结果,或是显式调用intern()方法的字符串才会入池。


二、单次拼接代码的优化与对象数量问题

再看这段代码:

String s = "hello"; 
int k = 100; 
s = s + " 123" + k;

JLS说编译器可能用StringBuilder优化,这点没错——主流编译器会把这段代码优化成类似下面的逻辑:

s = new StringBuilder(s).append(" 123").append(k).toString();

这里创建的新对象包括:1个StringBuilder实例、1个k转成的"100"临时String、1个toString()生成的最终String。但为啥没法确定具体数量和可回收数量?因为不同JVM版本或编译器的优化细节可能有差异,比如有些场景下可能会复用临时对象,但整体来说:

  • 池中的"hello"和" 123"属于字面量,不会被轻易回收;
  • 临时的"100"和StringBuilder实例,用完后没有其他引用,是可以被垃圾回收的;
  • 最终生成的那个String,只要后续没有其他强引用,也会被回收。

三、你的核心疑问解答

1. 未显式使用new的String是否都会进入字符串池?

当然不是!只有以下几种情况的字符串会自动进入字符串池:

  • 直接写的字符串字面量(比如"abc");
  • 编译期就能确定结果的常量拼接(比如"a" + "b"会被编译成"ab",直接入池);
  • 显式调用String.intern()方法的字符串。

像运行时拼接生成的字符串、基本类型转换生成的字符串,都不会自动入池,除非你手动调用intern()。

2. 循环生成的hello0、hello1等是否实际不会被垃圾回收?

不会的。这些都是运行时动态生成的String对象,没有被字符串池引用(因为没调用intern()),而且每次循环后,前一个str的引用会被新的字符串覆盖。比如第二次循环后,str指向"hello1",此时"hello0"没有任何强引用,就会被垃圾回收器标记为可回收对象,后续会被清理。

3. 字符串池字面量因存在隐式引用,直到程序结束才会被回收,此理解是否正确?

大部分场景下是对的,但有例外:

  • 字符串字面量存储在类的运行时常量池中,而类的Class对象会被加载它的ClassLoader引用。如果是系统类加载器加载的类(比如咱们写的普通类),ClassLoader不会被回收,所以字面量会一直有引用,直到程序结束才会被回收;
  • 但如果是自定义ClassLoader加载的类,当这个类被卸载时,对应的常量池里的字面量如果没有其他外部引用,就可以被垃圾回收。不过这种场景在普通应用里很少见,所以你的理解在日常开发中是成立的。

内容的提问来源于stack exchange,提问作者Jim C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:13:58