String ss = “BBB” + s + “CCC” + 10;
System.out.println(ss);
}
然后用javap命令反编译class文件,javap -verbose StringBuilderTest
查看字节码bytecode:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: ldc #2 // String AAA
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder.“”😦)V
10: ldc #5 // String BBB
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #7 // String CCC
21: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: bipush 10
26: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
29: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
32: astore_2
33: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
36: aload_2
37: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return
清楚的看到12、16、21、26行 编译器自动为我们优化,使用了StringBuilder的append连接字符串。
到这里我们明白了,虽然在源程序中使用了"+“,但在编译时编译器仍然将”+"转换成StringBuilder,在效率上和直接代码里用StringBuilder的append是一样的。 Studio为我们做提示是考虑到代码的简洁性。
在循环中使用连加
如果连接字符串行表达式很简单(如上面的顺序结构),那么"+"和StringBuilder基本是一样的,但如果结构比较复杂,如使用循环来连接字符串,那么产生的Java Byte Code就会有很大的区别。 现在给我们的代码加上一个for循环看看:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: ldc #2 // String AAA
2: astore_1
3: ldc #3 // String
5: astore_2
6: iconst_0
7: istore_3
8: iload_3 这里开始循环
9: bipush 10
11: if_icmpge 54
14: new #4 // class java/lang/StringBuilder
17: dup
18: invokespecial #5 // Method java/lang/StringBuilder.“”😦)V
21: aload_2
22: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: ldc #7 // String BBB
27: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: ldc #8 // String CCC
36: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: bipush 10
41: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
44: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
47: astore_2
48: iinc 3, 1
51: goto 8 跳转到第8行做循环
54: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
57: aload_2
58: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
61: return
从字节码我们可以看出,new StringBuilder是在循环内部进行的。 所以每次循环,都会创建一个StringBuilder,这与直接在代码中使用单一StringBuilder的append效率肯定要低很多了。
所以Studio会像我们意料的那样进行提示。
总结一下: 如果只是简单逻辑顺序连接字符串,可以使用String的“+”,因为编译器会为我们自动优化为StringBuilder,而Studio进行提示考虑的是,既然性能一样,那么就要考虑代码的可读性,使用连加+,代码更简洁,更容易理解;而如果在循环中进行字符串拼接,那么一定要使用StringBuilder类型,这样性能会优秀很多。
写在最后
对程序员来说,很多技术的学习都是“防御性”的。也就是说,我们是在为未来学习。我们学习新技术的目的,或是为了在新项目中应用,或仅仅是为了将来的面试。但不管怎样,一定不能“止步不前”,不能荒废掉。
![
文章以下内容会给出阿里与美团的面试题(答案+解析)、面试题库、Java核心知识点梳理等
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
识点梳理等
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!