编译器将字符串累加编译成StringBuilder

源代码

    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的字节码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值