测试环境: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.