Two code examples:
- Example 1:
public static void main(String[] args) { String testStr = "test"; String rst = testStr + 1 + "a" + "pig" + 2; System.out.println(rst); } 复制代码
- Example 2:
public static void main(String[] args) { String testStr = ""; for (int i = 0; i < 10; i++) { testStr += i + "test"; } System.out.println(testStr); } 复制代码
analysis:
- With javap decompile
例1
obtain the following bytecode class file code represents:
Javac automatically seen such a continuous string concatenation compiled into StringBuilder.append, and therefore do not have to deliberately written StringBuilder.append form when writing code;public static Method main:"([Ljava/lang/String;)V" stack 3 locals 3 { ldc String "test"; astore_1; new class java/lang/StringBuilder; dup; aload_1; invokestatic Method java/lang/String.valueOf:"(Ljava/lang/Object;)Ljava/lang/String;"; invokespecial Method java/lang/StringBuilder."<init>":"(Ljava/lang/String;)V"; iconst_1; invokevirtual Method java/lang/StringBuilder.append:"(I)Ljava/lang/StringBuilder;"; ldc String "a"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; ldc String "pig"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; iconst_2; invokevirtual Method java/lang/StringBuilder.append:"(I)Ljava/lang/StringBuilder;"; invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; astore_2; getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; aload_2; invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; return; } 复制代码
- With javap decompile
例2
obtain the following bytecode class file code represents:
A little long, a little I added some comments to read: javac still visible automatically cycle the body's string concatenation automatically compiled into StringBuilder.append, but please note thatpublic static Method main:"([Ljava/lang/String;)V" stack 3 locals 3 { ldc String ""; // 栈上来个空字符串 astore_1; // 栈顶元素弹出,放到局部变量1 iconst_0; // 栈上来个0 istore_2; // 栈顶元素弹出,放到局部变量2 goto L35; // 跳转到35行,此时栈空 L8: stack_frame_type append; locals_map class java/lang/String, int; new class java/lang/StringBuilder; // 栈上来个StringBuilder对象 dup; // 复制栈顶对象,也压入栈中(StringBuilder对象) aload_1; // 局部变量1压入栈中 invokestatic Method java/lang/String.valueOf:"(Ljava/lang/Object;)Ljava/lang/String;"; // 栈顶元素强转String invokespecial Method java/lang/StringBuilder."<init>":"(Ljava/lang/String;)V"; // 弹出栈顶2个元素,调用StringBuilder构造函数,剩下一个刚才复制的、现在已经初始化好的StringBuilder在栈顶 iload_2; // 局部变量2压入栈中:数字0 invokevirtual Method java/lang/StringBuilder.append:"(I)Ljava/lang/StringBuilder;"; // 数字0 append进栈顶StringBuilder,返回值StringBuilder放回栈顶 ldc String "test"; // 常量"test"压入栈中 invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; // “test”append进栈顶StringBuilder,返回值StringBuilder放回栈顶 invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; // 栈顶StringBuilder弹出,toString,String结果放入栈顶 astore_1; // String结果弹出放进局部变量1 iinc 2, 1; // 2号局部变量++ L35: stack_frame_type same; iload_2; // 2号局部变量放到栈顶 bipush 10; // 常量10压栈,作为栈顶 if_icmplt L8; // 弹出栈中前两个数,如果栈中第二个数比栈顶元素小,就跳到第8行,否则继续往下 getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; // PrintStream对象压入栈顶 aload_1; // 局部变量1压入栈顶(字符串) invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; // 弹出栈中2个数,以栈中第二个元素作为参数1(即this),栈顶元素作为参数2,调用println方法 return; } 复制代码
new class java/lang/StringBuilder;
this directive appears in theL8
label andL35
backif_icmplt L8;
between the jump instruction , that is to say: it circulates inside the body - again that is - the code is optimized for each cycle will again become a new StringBuilder do string concatenation, the number of loops, the number of StringBuilder object is created ; although this may not be a big deal of overhead, but it is still a programmer to write by hand the StringBuilder outside the loop, then the loop body using only append more cost-effective.
to sum up
Since modern javac compiler can automatically compiled to form StringBuilder.append string concatenation, and so usually the direct writing '+' sign to splice, but if the string needs to be spliced through a cycle, preferably the explicit StringBuilder then create circulation in vivo use, in order to avoid repeated StringBuilder object created in vitro cycle