StringBuilder的append、StringBuffer的append和String str = "a"+"b"的區別?


大家都知道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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM