Java 9循环字符串拼接:对象创建数、中间对象及验证方法咨询
关于循环中字符串拼接的对象创建问题拆解
嘿,这个问题问到点子上了,咱们结合Java版本差异一步步说清楚:
1. 循环中创建的对象数量(分Java版本)
首先得明确:循环外的初始空字符串""和List里的"a"/"b"/"c"属于常量池复用对象,不算循环内创建的。咱们只算循环过程中生成的对象:
Java 8 场景
每次result += n,编译器会把它翻译成等价的代码:
result = new StringBuilder(result).append(n).toString();
所以3次循环下来:
- 每次循环创建1个
StringBuilder对象,共3个 - 每次
toString()会生成1个新的String对象(因为String不可变,toString会基于拼接后的char数组新建String),共3个 - 总计:6个对象
Java 9+ 场景
Java 9引入了StringConcatFactory和invokedynamic优化字符串拼接,虽然底层实现更高效(比如直接用数组拼接、避免频繁扩容),但循环中的+=依然无法被编译器优化为单次拼接容器复用。每次循环还是会生成1个新的String对象,同时可能伴随少量临时数组/辅助对象(但核心可计数的对象还是3个新String)。
2. 是否存在中间对象?
肯定存在!
- Java 8中:每次循环生成的
StringBuilder和非最终的String对象(前两次循环的"a"、"ab")都是中间对象——它们仅作为拼接过渡,循环结束后就会变成垃圾被回收,只有最后一个"abc"被保留在result中。 - Java 9+中:虽然没有显式的
StringBuilder,但每次循环生成的临时String对象(同样是前两次的"a"、"ab")依然是中间对象,本质和Java 8一样,只是底层拼接方式更高效而已。
3. 如何验证这一点?
这里分享几个实用的验证方法:
方法1:查看编译后的字节码
用javac编译你的代码,然后执行javap -c 你的类名查看字节码指令:
- Java 8中,你会看到每次循环里都有
new StringBuilder、invokespecial StringBuilder.<init>、append、toString的指令,证明每次都在新建StringBuilder和String。 - Java 9+中,会看到
invokedynamic指令调用java.lang.invoke.StringConcatFactory.makeConcatWithConstants,但依然是每次循环执行一次这个调用,生成新的String。
方法2:监控内存与对象创建
把循环次数改成10000次(放大效果),然后用JVM参数追踪:
- 加上
-XX:+PrintGC运行程序,会看到频繁的小GC——这就是大量中间对象被回收导致的。 - 对比用单个
StringBuilder的写法(StringBuilder sb = new StringBuilder(); for(...) sb.append(n); String result = sb.toString();),你会发现GC次数大幅减少,因为没有了大量中间对象。
方法3:调试观察对象地址
在循环中打印System.identityHashCode(result),你会发现每次循环后result的哈希值都不一样——这说明每次都是新的String对象,证明中间对象存在。
内容的提问来源于stack exchange,提问作者D2k
相关产品推荐
相关产品推荐

