源代码
String aa = "aa";
String bb = "bb";
String cc = "cc";
String result = aa + bb + cc;
编译后
NEW StringBuilder
DUP
ALOAD 1: aa
INVOKESTATIC String.valueOf(Object) : String
INVOKESPECIAL StringBuilder.<init>(String) : void
ALOAD 2: bb
INVOKEVIRTUAL StringBuilder.append(String) : StringBuilder
ALOAD 3: cc
INVOKEVIRTUAL StringBuilder.append(String) : StringBuilder
INVOKEVIRTUAL StringBuilder.toString() : String
ASTORE 4: result
编译器将字符串累加编译成一个字符串
源代码
String s="aa"+"bb"+"cc";
编译后
LDC "aabbcc"
最佳实践:先拼接字符串再拼接变量
从上可知第二种字符串累加的效率更高。
aa + "bb"+"cc" 效率小于 "bb"+"cc"+aa。
因为"bb"+"cc"会先编译为"bbcc"。而aa + "bb" + "cc"中出现变量,
在变量后的字符串就会编译成StringBuilder。
源代码
String aa = "aa";
String result3 = aa + "bb"+"cc";
String result4 = "bb"+"cc"+aa;
编译后
L0 (0)
LDC "aa"
ASTORE 1: aa
L1 (3)
NEW StringBuilder
DUP
ALOAD 1: aa
INVOKESTATIC String.valueOf(Object) : String
INVOKESPECIAL StringBuilder.<init>(String) : void
LDC "bb"
INVOKEVIRTUAL StringBuilder.append(String) : StringBuilder
LDC "cc"
INVOKEVIRTUAL StringBuilder.append(String) : StringBuilder
INVOKEVIRTUAL StringBuilder.toString() : String
ASTORE 2: result3
L2 (15)
NEW StringBuilder
DUP
LDC "bbcc"
INVOKESPECIAL StringBuilder.<init>(String) : void
ALOAD 1: aa
INVOKEVIRTUAL StringBuilder.append(String) : StringBuilder
INVOKEVIRTUAL StringBuilder.toString() : String
ASTORE 3: result4
L3 (24)
RETURN
L4 (26)
最佳实践:在循环中不要使用累加操作
因为StringBuilder是在循环内创建的。建议手动在外面创建StringBuilder。 StringBuilder eqPhone = new StringBuilder();
// 将#转换为-
for (String phoneNum : wwPhone.split("#")) {
if (StringUtil.isNotBlank(phoneNum)) {
eqPhone.append(phoneNum).append("-");
}
}
解释如下:上面是源代码,下面是字节码分析
public static void a()
{
String s1="1";
for (int i = 0; i <10; i++) {
s1+="2";
}
}
0 ldc <String "1"> [56]//装载常量“1”到操作栈
2 astore_0 [s1] //存储常量到第一个位置
3 iconst_0 //装载常量0
4 istore_1 [i]//从操作栈存储常量到局部变量的第二个位置
5 goto 31//无条件跳转到31行
8 new java.lang.StringBuilder [54]//在循环内创建对象
11 dup//复制引用到栈 12 aload_0 [s1]//装载变量
13 invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [77]//调用valueOf静态方法
16 invokespecial java.lang.StringBuilder(java.lang.String) [58]调用StringBuilder构造方法
19 ldc <String "2"> [69]//装载常量2到操作栈
21 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [61]
24 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [65]
27 astore_0 [s1]//保存变量
28 iinc 1 1 [i]//第二个局部变量(也就是i)自增1
31 iload_1 [i]//从局部变量取第2个数,装载到操作栈
32 bipush 10 // 装载常量到操作栈
34 if_icmplt 8// if不满足就跳转到第8行
37 return
重点看这两行,就能发现在循环里每次都会new StringBuilder
8 new java.lang.StringBuilder [54]//在循环内创建对象
34 if_icmplt 8// if不满足就跳转到第8行
分析工具java asm
注:可用jdk自带的javap.exe的命令“javap -verbose 类名”来查看.class的字节码