字符串是什么样两个字符串相加究竟发⽣了什么⾸先从⼀张图开始,图中对字符串相加和StringBuild.append()做了性能对⽐。
有⼈说字符串每次相加都新建了⼀个对象所以慢,事情真的是这样吗?
先要了解真相最好的⽅法当然是反编译了,使⽤ javap -c 反编译的结果
public void test();
Code:
0: ldc #2 // String s1
2: astore_1
3: ldc #3 // String s2
5: astore_2
6: invokestatic #4 // Method java/lang/System.currentTimeMillis:()J
9: lstore_3
10: aload_1
11: invokevirtual #5 // Method java/lang/String.length:()I
14: ldc #6 // int 100000
16: if_icmpge 41
//虽然是字符串相加但是仍然创建了StringBuilder对象
19: new #7 // class java/lang/StringBuilder
22: dup
23: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
26: aload_1
27: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_2
31: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
//将拼接好的字符串重新复制给s1的时候 toString
34: invokevirtual #10 // Method java/String:()Ljava/lang/String;
//赋值给s1
37: astore_1
回到10,循环继续创建新的StringBuilder。然后toString
38: goto 10
41: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
44: invokestatic #4 // Method java/lang/System.currentTimeMillis:()J
47: lload_3
48: lsub
49: invokevirtual #12 // Method java/io/PrintStream.println:(J)V
// 下⾯是SringBuilder
52: invokestatic #4 // Method java/lang/System.currentTimeMillis:()J
55: lstore 5
// ⽣成⼀个StringBuilder
57: new #7 // class java/lang/StringBuilder
60: dup
61: ldc #2 // String s1
63: invokespecial #13 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
66: astore 7
68: aload 7
70: invokevirtual #14 // Method java/lang/StringBuilder.length:()I
73: ldc #6 // int 100000
75: if_icmpge 88
78: aload 7
80: aload_2
//调⽤append⽅法,不新建对象
81: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 84: pop
85: goto 68
88: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
91: invokestatic #4 // Method java/lang/System.currentTimeMillis:()J
94: lload 5
96: lsub
97: invokevirtual #12 // Method java/io/PrintStream.println:(J)V
100: return
这个时候你可能有疑问,这个循环执⾏了50000次,创建了50000个StringBuilder对象会慢这么多吗?
其实StringBuilder的toString⽅法会调⽤new String()也就是说会创建⼗万个对象,并且量变会引起质变,
⼗万个对象产⽣的耗时不仅是创建对象的耗时,还有gc的耗时,下⾯是gc⽇志
[GC (Allocation Failure) [PSYoungGen: 33280K->1576K(38400K)] 33280K->1584K(125952K), 0.0262659 secs] [Times: user=0.03 sys=0.02, real=0.03 secs] [GC (Allocation Failure) [PSYoungGen: 34856K->1224K(71680K)] 34864K->1240K(159232K), 0.0019681 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 67784K->1158K(71680K)] 67800K->1174K(159232K), 0.0094555 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 67718K->1118K(138240K)] 67734K->1134K(225792K), 0.0287607 secs] [Times: user=0.06 sys=0.00, real=0.03 secs] [GC (Allocation Failure) [PSYoungGen: 134238K->1155K
(138240K)] 134254K->1171K(225792K), 0.0214991 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 134275K->1109K(268288K)] 134291K->1125K(355840K), 0.0133364 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 267349K->69K(268288K)] 267365K->1163K(355840K), 0.0325131 secs] [Times: user=0.02 sys=0.02, real=0.03 secs] [GC (Allocation Failure) [PSYoungGen: 266309K->119K(534528K)] 267403K->1213K(622080K), 0.0109569 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 532599K->86K(534528K)] 533693K->1180K(622080K), 0.0294418 secs] [Times: user=0.00 sys=0.02, real=0.03 secs] [GC (Allocation Failure) [PSYoungGen: 532566K->221K(689152K)] 533660K->1315K(776704K), 0.0138167 secs] [Times: user=0.02 sys=0.01, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 687325K->177K(689152K)] 688419K->1271K(776704K), 0.0188002 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 687281K->113K(689152K)] 688375K->1207K(776704K), 0.0177870 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 687217K->121K(689152K)] 688311K->1215K(776704K), 0.0004647 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 687225K->128K(689152K)] 688319K->1222K(776704K), 0.0187945 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 687232K->238K(689152K)] 688326K->1332K(
776704K), 0.0005238 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 687342K->360K(689152K)] 688436K->1454K(776704K), 0.0004996 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 687464K->262K(689152K)] 688558K->1356K(776704K), 0.0010731 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 687366K->395K(688128K)] 688460K->1489K(775680K), 0.0014061 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 687499K->158K(688640K)] 688593K->1252K(776192K), 0.0160660 secs] [Times: user=0.05 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 687262K->427K(689664K)] 688356K->1520K(777216K), 0.0006749 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 688555K->305K(689664K)] 689648K->1398K(777216K), 0.0026644 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 688433K->314K(689664K)] 689526K->1408K(777216K), 0.0006023 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 688442K->178K(689664K)] 689536K->1271K(777216K), 0.0143623 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 688306K->333K(689664K)] 689399K->1426K(777216K), 0.0022489 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 688461K->341K(689664K)] 689554K->1435K(777216K), 0.0230670 secs] [Ti
mes: user=0.05 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 688469K->350K(688640K)] 689563K->1444K(776192K), 0.0205516 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 688478K->195K(689152K)] 689572K->1289K(776704K), 0.0035319 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 688323K->366K(690176K)] 689417K->1460K(777728K), 0.0115201 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 689518K->546K(690176K)] 690612K->1639K(777728K), 0.0176273 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] [GC (Allocation Failure) [PSYoungGen: 689698K->557K(690176K)] 690791K->1651K(777728K), 0.0018610 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 689709K->210K(690176K)] 690803K->1304K(777728K), 0.0134489 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 689362K->580K(690176K)] 690456K->1673K(777728K), 0.0004401 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 689732K->218K(690176K)] 690825K->1311K(777728K), 0.0015334 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 689370K->411K(690176K)] 690463K->1505K(777728K), 0.0006384 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 689563K->611K(690176K)] 690657K->1705K(777728K), 0.0005230 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
总结:
两个字符串相加底层会⽣成StringBuilder对象,然后使⽤append来拼接,如果不在循环中使⽤,可以不⽤StringBuilder,
但是养成使⽤StringBuilder的习惯能避免出现问题,如果使⽤idea的话,万能的alt+enter会⽴刻把字符串相加变成StringBuilder。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论