大家都知道String+String会开销额外的系统资源,粗略的原因是String是不可变类,每一步操作都会返回新的String变量,占用空间及时间。
其实我的理解不是这样的,我们来看看String+的底层实现。
测试案例
public static void main(String[] args) { String a = "a"; StringBuilder b = new StringBuilder("b"); StringBuffer c = new StringBuffer("c"); long star = System.currentTimeMillis(); for(int i=0;i<200000;i++){ a+="a"; } long end = System.currentTimeMillis(); System.out.println("String:"+(end-star)); star = System.currentTimeMillis(); for(int i=0;i<200000;i++){ b.append("b"); } end = System.currentTimeMillis(); System.out.println("StringBuilder:"+(end-star)); star = System.currentTimeMillis(); for(int i=0;i<200000;i++){ c.append("c"); } end = System.currentTimeMillis(); System.out.println("StringBuffer:"+(end-star)); }
测试结果
String:17735
StringBuilder:6
StringBuffer:7
测试结论
String+ 确实占用了太多的资源,处理效率非常低下。StringBuilder比StringBuffer更新了同步方法,性能有所提升。
原因分析
我用javap -verbose 查看已经编译好的class文件发现:
public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=6, locals=9, args_size=1 0: ldc #16 // String a 2: astore_1 3: new #18 // class java/lang/StringBuilder 6: dup 7: ldc #20 // String b 9: invokespecial #22 // Method java/lang/StringBuilder. <init>":(Ljava/lang/String;)V 12: astore_2 13: new #25 // class java/lang/StringBuffer 16: dup 17: ldc #27 // String c 19: invokespecial #29 // Method java/lang/StringBuffer." init>":(Ljava/lang/String;)V 22: astore_3 23: invokestatic #30 // Method java/lang/System.current imeMillis:()J 26: lstore 4 28: iconst_0 29: istore 6 31: goto 57 34: new #18 // class java/lang/StringBuilder 37: dup 38: aload_1 39: invokestatic #36 // Method java/lang/String.valueOf (Ljava/lang/Object;)Ljava/lang/String; 42: invokespecial #22 // Method java/lang/StringBuilder. <init>":(Ljava/lang/String;)V 45: ldc #16 // String a 47: invokevirtual #42 // Method java/lang/StringBuilder. ppend:(Ljava/lang/String;)Ljava/lang/StringBuilder; 50: invokevirtual #46 // Method java/lang/StringBuilder. oString:()Ljava/lang/String; 53: astore_1 54: iinc 6, 1 57: iload 6 59: ldc #50 // int 100000 61: if_icmplt 34 64: invokestatic #30 // Method java/lang/System.current imeMillis:()J 67: lstore 6 69: getstatic #51 // Field java/lang/System.out:Ljav /io/PrintStream; 72: new #18 // class java/lang/StringBuilder 75: dup 76: ldc #55 // String String: 78: invokespecial #22 // Method java/lang/StringBuilder. <init>":(Ljava/lang/String;)V 81: lload 6 83: lload 4 85: lsub 86: invokevirtual #57 // Method java/lang/StringBuilder. ppend:(J)Ljava/lang/StringBuilder; 89: invokevirtual #46 // Method java/lang/StringBuilder. oString:()Ljava/lang/String; 92: invokevirtual #60 // Method java/io/PrintStream.prin ln:(Ljava/lang/String;)V 95: invokestatic #30 // Method java/lang/System.current imeMillis:()J 98: lstore 4 100: iconst_0 101: istore 8 103: goto 116 106: aload_2 107: ldc #20 // String b 109: invokevirtual #42 // Method java/lang/StringBuilder. ppend:(Ljava/lang/String;)Ljava/lang/StringBuilder; 112: pop 113: iinc 8, 1 116: iload 8 118: ldc #50 // int 100000 120: if_icmplt 106 123: invokestatic #30 // Method java/lang/System.current imeMillis:()J 126: lstore 6 128: getstatic #51 // Field java/lang/System.out:Ljav /io/PrintStream; 131: new #18 // class java/lang/StringBuilder 134: dup 135: ldc #65 // String StringBuilder: 137: invokespecial #22 // Method java/lang/StringBuilder. <init>":(Ljava/lang/String;)V 140: lload 6 142: lload 4 144: lsub 145: invokevirtual #57 // Method java/lang/StringBuilder. ppend:(J)Ljava/lang/StringBuilder; 148: invokevirtual #46 // Method java/lang/StringBuilder. oString:()Ljava/lang/String; 151: invokevirtual #60 // Method java/io/PrintStream.prin ln:(Ljava/lang/String;)V 154: invokestatic #30 // Method java/lang/System.current imeMillis:()J 157: lstore 4 159: iconst_0 160: istore 8 162: goto 175 165: aload_3 166: ldc #27 // String c 168: invokevirtual #67 // Method java/lang/StringBuffer.a pend:(Ljava/lang/String;)Ljava/lang/StringBuffer; 171: pop 172: iinc 8, 1 175: iload 8 177: ldc #50 // int 100000 179: if_icmplt 165 182: invokestatic #30 // Method java/lang/System.current imeMillis:()J 185: lstore 6 187: getstatic #51 // Field java/lang/System.out:Ljav /io/PrintStream; 190: new #18 // class java/lang/StringBuilder 193: dup 194: ldc #70 // String StringBuffer: 196: invokespecial #22 // Method java/lang/StringBuilder. <init>":(Ljava/lang/String;)V 199: lload 6 201: lload 4 203: lsub 204: invokevirtual #57 // Method java/lang/StringBuilder. ppend:(J)Ljava/lang/StringBuilder; 207: invokevirtual #46 // Method java/lang/StringBuilder. oString:()Ljava/lang/String; 210: invokevirtual #60 // Method java/io/PrintStream.prin ln:(Ljava/lang/String;)V 213: return
从编译的代码来看,String+的准确操作是:
new StringBuilder()
new String.valueof()
StringBuilder.<init>
StringBuilder.append()
StringBuilder.toString()
而StringBuilder的准确操作是:
StringBuilder.append()
而StringBuffer()的准确操作是:
StringBuffer.append
转自http://alqm1314-126-com.iteye.com/blog/1932879