日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java中的StringBuilder类功能详解

發布時間:2024/4/15 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中的StringBuilder类功能详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

字符串是Java程序中最常用的一種數據結構之一。在Java中的String類已經重載的"+"。也就是說,字符串可以直接使用"+"進行連接,如下面代碼所示:

  • String?s?=?"abc"?+?"ddd";?
  • 但這樣做真的好嗎?當然,這個問題不能簡單地回答yes or no。要根據具體情況來定。在Java中提供了一個StringBuilder類(這個類只在J2SE5及以上版本提供,以前的版本使用StringBuffer類),這個類也可以起到"+"的作用。那么我們應該用哪個呢?

    下面讓我們先看看如下的代碼:

  • package?string; ?
  • ?? ?
  • ??public?class?TestSimplePlus ?
  • ??{ ?
  • ??????public?static?void?main(String[]?args) ?
  • ??????{ ?
  • ??????????String?s?=?"abc"; ?
  • ??????????String?ss?=?"ok"?+?s?+?"xyz"?+?5; ?
  • ??????????System.out.println(ss); ?
  • ??????} ?
  • ??}?
  • 上面的代碼將會輸出正確的結果。從表面上看,對字符串和整型使用"+"號并沒有什么區別,但事實真的如此嗎?下面讓我們來看看這段代碼的本質。

    我們首先使用反編譯工具(如jdk帶的javap、或jad)將TestSimplePlus反編譯成Java Byte Code,其中的奧秘就一目了然了。在本文將使用jad來反編譯,命令如下:

    jad -o -a -s d.java TestSimplePlus.class

    反編譯后的代碼如下:

  • package?string; ?
  • ?
  • import?java.io.PrintStream; ?
  • ?
  • public?class?TestSimplePlus ?
  • { ?
  • ????public?TestSimplePlus() ?
  • ????{ ?
  • ????//????0????0:aload_0????????? ?
  • ????//????1????1:invokespecial???#8???<?Method?void?Object()> ?
  • ????//????2????4:return?????????? ?
  • ????} ?
  • ?
  • ????public?static?void?main(String?args[]) ?
  • ????{ ?
  • ??????String?s?=?"abc"; ?
  • ????//????0????0:ldc1????????????#16??<?String?"abc"> ?
  • ????//????1????2:astore_1???????? ?
  • ??????String?ss?=?(new?StringBuilder("ok")).append(s).append("xyz").append(5).toString(); ?
  • ????//????2????3:new?????????????#18??<?Class?StringBuilder> ?
  • ????//????3????6:dup????????????? ?
  • ????//????4????7:ldc1????????????#20??<?String?"ok"> ?
  • ????//????5????9:invokespecial???#22??<?Method?void?StringBuilder(String)> ?
  • ????//????6???12:aload_1????????? ?
  • ????//????7???13:invokevirtual???#25??<?Method?StringBuilder?StringBuilder.append(String)> ?
  • ????//????8???16:ldc1????????????#29??<?String?"xyz"> ?
  • ????//????9???18:invokevirtual???#25??<?Method?StringBuilder?StringBuilder.append(String)> ?
  • ????//???10???21:iconst_5???????? ?
  • ????//???11???22:invokevirtual???#31??<?Method?StringBuilder?StringBuilder.append(int)> ?
  • ????//???12???25:invokevirtual???#34??<?Method?String?StringBuilder.toString()> ?
  • ????//???13???28:astore_2???????? ?
  • ??????System.out.println(ss); ?
  • ????//???14???29:getstatic???????#38??<?Field?PrintStream?System.out> ?
  • ????//???15???32:aload_2????????? ?
  • ????//???16???33:invokevirtual???#44??<?Method?void?PrintStream.println(String)> ?
  • ????//???17???36:return?????????? ?
  • ????} ?
  • } ?
  • 讀者可能看到上面的Java字節碼感到迷糊,不過大家不必擔心。本文的目的并不是講解Java Byte Code,因此,并不用了解具體的字節碼的含義。

    使用jad反編譯的好處之一就是可以同時生成字節碼和源代碼。這樣可以進行對照研究。從上面的代碼很容易看出,雖然在源程序中使用了"+",但在編譯時仍然將"+"轉換成StringBuilder。因此,我們可以得出結論,在Java中無論使用何種方式進行字符串連接,實際上都使用的是StringBuilder類。

    那么是不是可以根據這個結論推出使用"+"和StringBuilder類的效果是一樣的呢?這個要從兩個方面的解釋。如果從運行結果來解釋,那么"+"和StringBuilder是完全等效的。但如果從運行效率和資源消耗方面看,那它們將存在很大的區別。

    當然,如果連接字符串行表達式很簡單(如上面的順序結構),那么"+"和StringBuilder類基本是一樣的,但如果結構比較復雜,如使用循環來連接字符串,那么產生的Java Byte Code就會有很大的區別。先讓我們看看如下的代碼:

  • package?string; ?
  • ? ?
  • ?import?java.util.*; ?
  • ? ?
  • ?public?class?TestComplexPlus ?
  • ?{ ?
  • ?????public?static?void?main(String[]?args) ?
  • ?????{ ?
  • ?????????String?s?=?""; ?
  • ?????????Random?rand?=?new?Random(); ?
  • ?????????for?(int?i?=?0;?i?<??10;?i++) ?
  • ?????????{ ?
  • ?????????????s?=?s?+?rand.nextInt(1000)?+?"?"; ?
  • ?????????} ?
  • ?????????System.out.println(s); ?
  • ?????} ?
  • ?}?
  • 上面的代碼返編譯后的Java Byte Code如下:

  • package?string; ?
  • ?
  • import?java.io.PrintStream; ?
  • import?java.util.Random; ?
  • ?
  • public?class?TestComplexPlus ?
  • { ?
  • ?
  • ????public?TestComplexPlus() ?
  • ????{ ?
  • ????//????0????0:aload_0????????? ?
  • ????//????1????1:invokespecial???#8???<?Method?void?Object()> ?
  • ????//????2????4:return?????????? ?
  • ????} ?
  • ?
  • ????public?static?void?main(String?args[]) ?
  • ????{ ?
  • ????????String?s?=?""; ?
  • ????//????0????0:ldc1????????????#16??<?String?""> ?
  • ????//????1????2:astore_1???????? ?
  • ????????Random?rand?=?new?Random(); ?
  • ????//????2????3:new?????????????#18??<?Class?Random> ?
  • ????//????3????6:dup????????????? ?
  • ????//????4????7:invokespecial???#20??<?Method?void?Random()> ?
  • ????//????5???10:astore_2???????? ?
  • ????????for(int?i?=?0;?i?<??10;?i++) ?
  • ????//*???6???11:iconst_0???????? ?
  • ????//*???7???12:istore_3???????? ?
  • ????//*???8???13:goto????????????49 ?
  • ?????????s?=?(new?StringBuilder(String.valueOf(s))).append(rand.nextInt(1000)).append("?").toString(); ?
  • ????//????9???16:new?????????????#21??<?Class?StringBuilder> ?
  • ????//???10???19:dup????????????? ?
  • ????//???11???20:aload_1????????? ?
  • ????//???12???21:invokestatic????#23??<?Method?String?String.valueOf(Object)> ?
  • ????//???13???24:invokespecial???#29??<?Method?void?StringBuilder(String)> ?
  • ????//???14???27:aload_2????????? ?
  • ????//???15???28:sipush??????????1000 ?
  • ????//???16???31:invokevirtual???#32??<?Method?int?Random.nextInt(int)> ?
  • ????//???17???34:invokevirtual???#36??<?Method?StringBuilder?StringBuilder.append(int)> ?
  • ????//???18???37:ldc1????????????#40??<?String?"?"> ?
  • ????//???19???39:invokevirtual???#42??<?Method?StringBuilder?StringBuilder.append(String)> ?
  • ????//???20???42:invokevirtual???#45??<?Method?String?StringBuilder.toString()> ?
  • ????//???21???45:astore_1???????? ?
  • ?
  • ????//???22???46:iinc????????????3??1 ?
  • ????//???23???49:iload_3????????? ?
  • ????//???24???50:bipush??????????10 ?
  • ????//???25???52:icmplt??????????16 ?
  • ????????System.out.println(s); ?
  • ????//???26???55:getstatic???????#49??<?Field?PrintStream?System.out> ?
  • ????//???27???58:aload_1????????? ?
  • ????//???28???59:invokevirtual???#55??<?Method?void?PrintStream.println(String)> ?
  • ????//???29???62:return?????????? ?
  • ????} ?
  • } ?
  • 大家可以看到,雖然編譯器將"+"轉換成了StringBuilder類,但創建StringBuilder對象的位置卻在for語句內部。這就意味著每執行一次循環,就會創建一個StringBuilder對象(對于本例來說,是創建了10個StringBuilder對象),雖然Java有垃圾回收器,但這個回收器的工作時間是不定的。如果不斷產生這樣的垃圾,那么仍然會占用大量的資源。解決這個問題的方法就是在程序中直接使用StringBuilder類來連接字符串,代碼如下:

  • package?string; ?
  • ?
  • import?java.util.*; ?
  • ?
  • public?class?TestStringBuilder ?
  • { ?
  • ????public?static?void?main(String[]?args) ?
  • ????{ ?
  • ????????String?s?=?""; ?
  • ????????Random?rand?=?new?Random(); ?
  • ????????StringBuilder?result?=?new?StringBuilder(); ?
  • ????????for?(int?i?=?0;?i?<??10;?i++) ?
  • ????????{ ?
  • ????????????result.append(rand.nextInt(1000)); ?
  • ????????????result.append("?"); ?
  • ????????} ?
  • ????????System.out.println(result.toString()); ?
  • ????} ?
  • } ?
  • 上面代碼反編譯后的結果如下:

  • package?string; ?
  • ?
  • import?java.io.PrintStream; ?
  • import?java.util.Random; ?
  • ?
  • public?class?TestStringBuilder ?
  • { ?
  • ?
  • ????public?TestStringBuilder() ?
  • ????{ ?
  • ????//????0????0:aload_0????????? ?
  • ????//????1????1:invokespecial???#8???<?Method?void?Object()> ?
  • ????//????2????4:return?????????? ?
  • ????} ?
  • ?
  • ????public?static?void?main(String?args[]) ?
  • ????{ ?
  • ????????String?s?=?""; ?
  • ????//????0????0:ldc1????????????#16??<?String?""> ?
  • ????//????1????2:astore_1???????? ?
  • ????????Random?rand?=?new?Random(); ?
  • ????//????2????3:new?????????????#18??<?Class?Random> ?
  • ????//????3????6:dup????????????? ?
  • ????//????4????7:invokespecial???#20??<?Method?void?Random()> ?
  • ????//????5???10:astore_2???????? ?
  • ????????StringBuilder?result?=?new?StringBuilder(); ?
  • ????//????6???11:new?????????????#21??<?Class?StringBuilder> ?
  • ????//????7???14:dup????????????? ?
  • ????//????8???15:invokespecial???#23??<?Method?void?StringBuilder()> ?
  • ????//????9???18:astore_3???????? ?
  • ????????for(int?i?=?0;?i?<??10;?i++) ?
  • ????//*??10???19:iconst_0???????? ?
  • ????//*??11???20:istore??????????4 ?
  • ????//*??12???22:goto????????????47 ?
  • ????????{ ?
  • ????????????result.append(rand.nextInt(1000)); ?
  • ????//???13???25:aload_3????????? ?
  • ????//???14???26:aload_2????????? ?
  • ????//???15???27:sipush??????????1000 ?
  • ????//???16???30:invokevirtual???#24??<?Method?int?Random.nextInt(int)> ?
  • ????//???17???33:invokevirtual???#28??<?Method?StringBuilder?StringBuilder.append(int)> ?
  • ????//???18???36:pop????????????? ?
  • ????????????result.append("?"); ?
  • ????//???19???37:aload_3????????? ?
  • ????//???20???38:ldc1????????????#32??<?String?"?"> ?
  • ????//???21???40:invokevirtual???#34??<?Method?StringBuilder?StringBuilder.append(String)> ?
  • ????//???22???43:pop????????????? ?
  • ????????} ?
  • ?
  • ????//???23???44:iinc????????????4??1 ?
  • ????//???24???47:iload???????????4 ?
  • ????//???25???49:bipush??????????10 ?
  • ????//???26???51:icmplt??????????25 ?
  • ????????System.out.println(result.toString()); ?
  • ????//???27???54:getstatic???????#37??<?Field?PrintStream?System.out> ?
  • ????//???28???57:aload_3????????? ?
  • ????//???29???58:invokevirtual???#43??<?Method?String?StringBuilder.toString()> ?
  • ????//???30???61:invokevirtual???#47??<?Method?void?PrintStream.println(String)> ?
  • ????//???31???64:return?????????? ?
  • ????} ?
  • } ?
  • 從上面的反編譯結果可以看出,創建StringBuilder的代碼被放在了for語句外。雖然這樣處理在源程序中看起來復雜,但卻換來了更高的效率,同時消耗的資源也更少了。

    在使用StringBuilder類時要注意,盡量不要"+"和StringBuilder混著用,否則會創建更多的StringBuilder對象,如下面代碼所:

  • for?(int?i?=?0;?i?<??10;?i++) ?
  • { ?
  • ????result.append(rand.nextInt(1000)); ?
  • ????result.append("?"); ?
  • }?
  • 改成如下形式:

  • for?(int?i?=?0;?i?<??10;?i++) ?
  • { ?
  • ?????result.append(rand.nextInt(1000)?+?"?"); ?
  • } ?
  • ?
  • 則反編譯后的結果如下:

  • ?for(int?i?=?0;?i?<??10;?i++) ?
  • //*??10???19:iconst_0???????? ?
  • //*??11???20:istore??????????4 ?
  • //*??12???22:goto????????????65 ?
  • ?{ ?
  • ??result.append((new?StringBuilder(String.valueOf(rand.nextInt(1000)))).append("?").toString()); ?
  • //???13???25:aload_3????????? ?
  • //???14???26:new?????????????#21??<?Class?StringBuilder> ?
  • //???15???29:dup??????????????
  • 從上面的代碼可以看出,Java編譯器將"+"編譯成了StringBuilder類,這樣for語句每循環一次,又創建了一個StringBuilder對象。

    如果將上面的代碼在JDK1.4下編譯,必須將StringBuilder改為StringBuffer,而JDK1.4將"+"轉換為StringBuffer(因為JDK1.4并沒有提供StringBuilder類)。StringBuffer和StringBuilder的功能基本一樣,只是StringBuffer是線程安全的,而StringBuilder不是線程安全的。因此,StringBuilder的效率會更高。

    轉自:http://developer.51cto.com/art/200906/132698.htm

    總結

    以上是生活随笔為你收集整理的Java中的StringBuilder类功能详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。