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

来源:互联网 发布:mac os 10.13 开机慢 编辑:程序博客网 时间:2024/06/08 18:45

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

        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.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;      17: ldc           #7                  // String o      19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;      22: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()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.append:(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.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;      57: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;      60: if_acmpne     67      63: iconst_1      64: goto          68      67: iconst_0      68: invokevirtual #12                 // Method java/io/PrintStream.println:(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.println:(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.println:(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创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则导致浪费池的空间)
0 0