用一个我多次遇到的字符串题目来说明:
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
吧
最后补充一下字符串的创建过程:
- ” ” 引号创建的字符串在字符串池中
- new,new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则导致浪费池的空间)