Java中字符串String的+和+=及循环操作String原理详解
String对象是不可变的:意思就是无论是对String的新增或修改,出现一个全新的String内容时,都意味着诞生了一个新的对象。但是如果内容不变的话,增加的只是对象的引用而已。
例如:
String a = "ljh"; String b = "ljh"; String c = "ljh"; System.out.println(a==b); System.out.println(b==c);
结果都是true
但是这种不可变性会产生一些性能上的问题,所以JVM对String对象重载“+”“+=”进行了一些优化
操作符“+”可以用来连接String
String aaa = "ljh"; String bbb = "big"; String ccc = aaa+bbb+"aaaa";
在jdk8中,上述代码中在底层其实是编译器擅自调用了StringBuilder类进行+的操作,主要原因是StringBuilder的append()更加高效,我们来看一下字节码。
public static void main(java.lang.String[]); Code: 0: ldc #2 // String ljh 2: astore_1 3: ldc #3 // String big 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: ldc #7 // String aaaa 23: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 26: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 29: astore_3 30: return
可以看出一共有四个对象,分别是三个String 和一个StringBuilder
我们再来看一下+=
String a = "aaa"; a += "bbb";
字节码如下
Code:
0: ldc #2 // String aaa
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String bbb
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_1
23: return
可以看出先创建了一个“aaa”字符串,然后当a遇到+=时,创建了一个StringBuilder对象,并append了aaa字符串。之后创建了一个“bbb”对象,然后append了bbb字符串,最后调用StringBuilder的toString方法。
接下来再看看循环中调用+=会是什么样子
String a = "aaa"; a += "bbb"; for(int i=0;i<5;i++){ a+="ccc"; }
Code:
0: ldc #2 // String aaa
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String bbb
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_1
23: iconst_0
24: istore_2
25: iload_2
26: iconst_5
27: if_icmpge 56
30: new #3 // class java/lang/StringBuilder
33: dup
34: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
37: aload_1
38: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: ldc #8 // String ccc
43: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
46: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
49: astore_1
50: iinc 2, 1
53: goto 25
56: return
可以看出先创建String对象aaa,之后创建StringBuilder并初始化StringBuilder append aaa,然后创建bbb对象,并append( bbb),然后我们发现在循环中依旧创建了一个新的StringBuilder,也就是没经过一次循环都要创建一个新的StringBuilder对象。
这时我们做一个优化,提前创建StringBuilder对象
String a = "aaa"; a += "bbb"; StringBuilder sb = new StringBuilder(a); for(int i=0;i<5;i++){ sb.append("ccc"); }
Code:
0: ldc #2 // String aaa
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String bbb
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_1
23: new #3 // class java/lang/StringBuilder
26: dup
27: aload_1
28: invokespecial #8 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
31: astore_2
32: iconst_0
33: istore_3
34: iload_3
35: iconst_5
36: if_icmpge 52
39: aload_2
40: ldc #9 // String ccc
42: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
45: pop
46: iinc 3, 1
49: goto 34
52: return
可以看出循环体跳回34行,并不会不断地创建新的StringBuilder,大大提高了效率和减小了垃圾数量!,所以我们要注意自己的写法!避免无谓的消耗
总结
到此这篇关于Java中字符串String的+和+=及循环操作String原理的文章就介绍到这了,更多相关Java字符串String+和+=内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!