测试环境:Liberia OpenJDK 1.8 11 17

偶然知乎刷到一个面试题的讨论https://www.zhihu.com/question/50211894/answer/2395077963

这里说String s = new String("a") + new String("b")
答案是:2-5个(可能有误,没细想)

这里答主的答案是1.8已经优化成StringBuilder创建了,因为String在JDK9 底层发生了一些改变,所以拿高一点版本的JDK进行测试看看字节码文件
测试程序

public class Main {
  public static void main(String[] args) {
    // write your code here
    String s = new String("a") + new String("b");
  }
}

先展示1.8的字节码文件

 0 new #2 <java/lang/StringBuilder>
 3 dup
 4 invokespecial #3 <java/lang/StringBuilder.<init> : ()V>
 7 new #4 <java/lang/String>
10 dup
11 ldc #5 <a>
13 invokespecial #6 <java/lang/String.<init> : (Ljava/lang/String;)V>
16 invokevirtual #7 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
19 new #4 <java/lang/String>
22 dup
23 ldc #8 <b>
25 invokespecial #6 <java/lang/String.<init> : (Ljava/lang/String;)V>
28 invokevirtual #7 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
31 invokevirtual #9 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
34 astore_1
35 return

这里很明显的使用StringBuilder进行了拼接,这里显示是New3个

接下来测试在JDK11的情况
测试程序也如上所述
直接给出字节码文件

 0 new #2 <java/lang/String>
 3 dup
 4 ldc #3 <a>
 6 invokespecial #4 <java/lang/String.<init> : (Ljava/lang/String;)V>
 9 new #2 <java/lang/String>
12 dup
13 ldc #5 <b>
15 invokespecial #4 <java/lang/String.<init> : (Ljava/lang/String;)V>
18 invokedynamic #6 <makeConcatWithConstants, BootstrapMethods #0>
23 astore_1
24 return

可以看出这里使用了String的拼接,即使用invokedynamic来进行String字符串的拼接,减少了指令的数量

接下来测试下JDK17的情况
测试用例依旧如上
字节码文件效果如

 0 new #7 <java/lang/String>
 3 dup
 4 ldc #9 <a>
 6 invokespecial #11 <java/lang/String.<init> : (Ljava/lang/String;)V>
 9 new #7 <java/lang/String>
12 dup
13 ldc #14 <b>
15 invokespecial #11 <java/lang/String.<init> : (Ljava/lang/String;)V>
18 invokedynamic #16 <makeConcatWithConstants, BootstrapMethods #0>
23 astore_1
24 return

与上方的引用不同,但使用的是同一种方法

搜索了下google
https://www.baeldung.com/java-string-concatenation-invoke-dynamic
这篇文章给出了更充足的解释

Q.E.D.