JVM-为什么字符串拼接效率低
1. 源码准备
- 首先编写两个方法一个使用字符串拼接,一个使用StringBuilder进行拼接;
public class hello {
public void concatStrByDefault() {
String basic = "name ";
for (int i = 0; i < 100; i++) {
basic += i;
}
System.out.println(basic);
}
public void concatStrByBuilder() {
StringBuilder basic = new StringBuilder("name ");
for (int i = 0; i < 100; i++) {
basic.append(i);
}
System.out.println(basic.toString());
}
}
2.字节码指令层面解析
-
一上代码的执行时间长短我就不在重复测试了相信大家都会,接下来我们来一起看看这两个方法字节码指令
-
concatStrByDefault方法的字节码指令如下
- 简单解释下循环是在33行的goto指令调到第5行这样不断循环;并且在11行也就是循环中不断的通过new创建了StringBuilder对象,也就是循环了多少次就创建了多少个StringBuilder对象,并且如果大家看了我之前写字符串拼接原理,在StringBuilder的toString方法中还new了一个String对象;这里这么多对象的创建就必然需要垃圾回收效率自然就低了
0 ldc #2 <name > 2 astore_1 3 iconst_0 4 istore_2 5 iload_2 6 bipush 100 8 if_icmpge 36 (+28) 11 new #3 <java/lang/StringBuilder> 14 dup 15 invokespecial #4 <java/lang/StringBuilder.<init>> 18 aload_1 19 invokevirtual #5 <java/lang/StringBuilder.append> 22 iload_2 23 invokevirtual #6 <java/lang/StringBuilder.append> 26 invokevirtual #7 <java/lang/StringBuilder.toString> 29 astore_1 30 iinc 2 by 1 33 goto 5 (-28) 36 getstatic #8 <java/lang/System.out> 39 aload_1 40 invokevirtual #9 <java/io/PrintStream.println> 43 return
-
concatStrByBuilder方法的字节码指令
- 此处循环在27行的goto指令跳到12行,并且循环之间是没有创建新对象的,紧紧只是调用了append方法,这里就能很明显的看出这种方式比普通拼接少创建了很多的对象
0 new #3 <java/lang/StringBuilder> 3 dup 4 ldc #2 <name > 6 invokespecial #10 <java/lang/StringBuilder.<init>> 9 astore_1 10 iconst_0 11 istore_2 12 iload_2 13 bipush 100 15 if_icmpge 30 (+15) 18 aload_1 19 iload_2 20 invokevirtual #6 <java/lang/StringBuilder.append> 23 pop 24 iinc 2 by 1 27 goto 12 (-15) 30 getstatic #8 <java/lang/System.out> 33 aload_1 34 invokevirtual #7 <java/lang/StringBuilder.toString> 37 invokevirtual #9 <java/io/PrintStream.println> 40 return
3. 总结
- 拼接效率低的主要原因也就是每一次拼接都创建了一个StringBuilder对象,并且在赋值是又需要调用toString方法,而toString方法的实现里面有new了一个String对象,所以拼接的效率很低