String拼接符"+"在编译期做了什么?

用一个我多次遇到的字符串题目来说明:

        String a="hello";
        String b="hell";
        String c=b+"o";
        String d="hell"+"o";

        System.out.println(a==b+new String("o"));
        System.out.println(a==c);
        System.out.println(a==d);

输出结果为:

false
false
true

为什么是这个结果呢?我们看一下反编译后的代码分析下:

    Code:
       0: ldc           #2                  // String hello
       2: astore_1
       3: ldc           #3                  // String hell
       5: astore_2
       6: new           #4                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #5                  // Method java/lang/StringBuilder."<
init>":()V
      13: aload_2
      14: invokevirtual #6                  // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: ldc           #7                  // String o
      19: invokevirtual #6                  // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: invokevirtual #8                  // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
      25: astore_3
      26: ldc           #2                  // String hello
      28: astore        4
      30: getstatic     #9                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      33: aload_1
      34: new           #4                  // class java/lang/StringBuilder
      37: dup
      38: invokespecial #5                  // Method java/lang/StringBuilder."<
init>":()V
      41: aload_2
      42: invokevirtual #6                  // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      45: new           #10                 // class java/lang/String
      48: dup
      49: ldc           #7                  // String o
      51: invokespecial #11                 // Method java/lang/String."<init>":
(Ljava/lang/String;)V
      54: invokevirtual #6                  // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      57: invokevirtual #8                  // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
      60: if_acmpne     67
      63: iconst_1
      64: goto          68
      67: iconst_0
      68: invokevirtual #12                 // Method java/io/PrintStream.printl
n:(Z)V
      71: getstatic     #9                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      74: aload_1
      75: aload_3
      76: if_acmpne     83
      79: iconst_1
      80: goto          84
      83: iconst_0
      84: invokevirtual #12                 // Method java/io/PrintStream.printl
n:(Z)V
      87: getstatic     #9                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      90: aload_1
      91: aload         4
      93: if_acmpne     100
      96: iconst_1
      97: goto          101
     100: iconst_0
     101: invokevirtual #12                 // Method java/io/PrintStream.printl
n:(Z)V
     104: return

通过反编译的代码我们可以发现

String d="hell"+"o"在编译时就已经把d当成了hello,指向的是字符串常量池中的对象,所以a==d为TRUE。

String c=b+"o"b+new String("o")只要字符串拼接中有对象时,就会创建StringBuilder对象,然后用append方法拼接,最后调用StringBuilder的toString方法返回一个重新创建的字符串。所以与a比较为FALSE。

说到这里,可能会有疑问,既然+是用的StringBuilder进行拼接,那为什么当大量用到字符串拼接时,我们会说用+性能低,要用专门的StringBuilder类?

有兴趣的朋友可以反编译下这两种拼接的代码进行对比。当大量拼接字符串时,+会循环创建StringBuilder类,所以不如只创建了一个的StringBuilder性能高。也就是说编译器对+的优化是有限的,大量拼接字符串还是使用StringBuilder

最后补充一下字符串的创建过程:

  1. ” ” 引号创建的字符串在字符串池中
  2. new,new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则导致浪费池的空间)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值