字符串拼接

在开发过程中,字符串拼接的使用时非常频繁的,常用的方式有三种:

  • +号拼接:str + “456”
  • StringBuilder拼接
  • StringBUffer拼接
    StringBuffer是保证线程安全的,效率是比较低的,我们更多的使用场景是不会涉及到线程安全的问题的,所以更多的时候会选择StringBuilder,效率会高一些。那么问题来了,StringBuilder和“+”号拼接,哪个效率更高呢?我们可以通过字节码的方式进行研究一下。

首先编写实例代码:

public class Test3 {
    public void m1() {
        String s1 = "123";
        String s2 = "456";
        String s3 = s1 + s2;
        System.out.println(s3);
    }
    public void m2() {
        String s1 = "123";
        String s2 = "456";
        StringBuilder sb = new StringBuilder();
        sb.append(s1);
        sb.append(s2);
        String s3 = sb.toString();
        System.out.println(s3);
    }
    public static void main(String[] args) {
        new Test3().m1();
        new Test3().m2();
    }
}

查看class的字节码(不知道怎么查看的同学可以看看JVM字节码
我们主要看m1和m2的字节码,
“+”号拼接

0: ldc  #2                  // String 123
2: astore_1
3: ldc           #3                  // String 456
5: astore_2
6: new           #4                  // class java/lang/StringBuilder
9: dup
10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: return

StringBuilder拼接

 0: ldc           #2                  // String 123
 2: astore_1
 3: ldc           #3                  // String 456
 5: astore_2
 6: new           #4                  // class java/lang/StringBuilder
 9: dup
10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
13: astore_3
14: aload_3
15: aload_1
16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: aload_3
21: aload_2
22: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: pop
26: aload_3
27: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore        4
32: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
35: aload         4
37: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return

可以看到,“+”号拼接的字节码在第10步的时候调用了StringBuilder的方法,也就是说“+”号拼接在底层也是默认用StringBuilder方法的,所以“+”号和StringBuilder的效率是一样的。

我们来研究一下,在下面的情况下,“+”号和StringBuilder哪个效率更高呢?

代码:

在这里插入代码片

查看字节码
“+”号的字节码

0: ldc #6 						// String
2: astore_1 					// 将空字符串压入到本地变量表中的下标为1的位置
3: iconst_0 					// 将数字0压入操作栈顶
4: istore_2 					// 将栈顶数字0压入到本地变量表中的下标为2的位置
5: iload_2 						// 将本地变量中下标为2的数字0压入操作栈顶
6: iconst_5 					// 将数字5压入操作栈顶
7: if_icmpge 35 				//比较栈顶两int型数值大小,当结果大于等于0时跳转到35
10: new #7 						// class java/lang/StringBuilder
13: dup 						//复制栈顶数值并将复制值压入栈顶(数字5)
14: invokespecial #8 			// Method java/lang/StringBuilder."<init>":()V
17: aload_1
18: invokevirtual #9 			// Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
21: iload_2 					//将本地变量中下标为2的数字0压入操作栈顶
22: invokevirtual #10 			// Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
25: invokevirtual #11 			// Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: astore_1
29: iinc 2, 1
32: goto 5
35: getstatic #12 				// Field java/lang/System.out:Ljava/io/PrintStream;
38: aload_1
39: invokevirtual #13 			// Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: return

StringBuilder的字节码

0: new           #3                  // class java/lang/StringBuilder
3: dup
4: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
7: astore_1
8: iconst_0
9: istore_2
10: iload_2
11: iconst_5
12: if_icmpge     27
15: aload_1
16: iload_2
17: invokevirtual #6                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
20: pop
21: iinc          2, 1
24: goto          10
27: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
30: aload_1
31: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
34: return

可以看到,m1()方法中的循环体内,每一次循环都会创建StringBuilder对象,效率低于m2()方法。

使用字节码的方式可以很好地查看代码底层的执行,从而可以看出哪些实现效率高,哪些实现效率低。可以更好的对我们的代码做优化,让程序执行效率更好。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值