String、StringBuilder和StringBuffer的區別

1         String、StringBuilder和StringBuffer的區別

  String、StringBuilder、StringBuffer均可以用來保存字符串。若是是使用次數比較少的變量,三者皆可。若是存在大量的循環疊加調用。String循環累加字符串時,實際內部每循環一次就會new一個StringBuilder變量,而後調用StringBuilder的函數append去添加。因此會在堆上建立出不少個StringBuilder對象,形成不少垃圾。因此循環累加字符串時最好使用StringBuilder。StringBuilder和StringBuffer相似,只是StringBuffer是線程安全的。因此在多線程使用中,採用StringBuffer。StringBuilder比String的效率高,形成的內存垃圾少。StringBuffer效率和Stringbuilder效率差很少,StringBuffer是線程安全的。html

String內部是經過char數組來保存數據的,類的操做方法substr、replace等都須要從新new一個新的char數組來保存,不會對原String對象產生影響。java

String str1 = "hello world";這樣定義的字符常量存儲在常量池中,常量池中相同的字符串只有一個備份。在棧上建立的多個引用能夠指向相同的常量,只能更改引用指向不一樣的常量,不能修改引用指向的常量值。數組

String str2 = new String("hello world");字符串對象是在堆區進行的,而在堆區進行對象生成的過程是不會去檢測該對象是否已經存在的。安全

 

1.1  循環累加效率

1.1.1            String循環累加

String string = "";多線程

for(int i=0;i<10000;i++)app

{函數

  string += "hello";性能

}測試

從下面反編譯出的字節碼文件能夠很清楚地看出:從第8行開始到第35行是整個循環的執行過程,而且每次循環會new出一個StringBuilder對象,而後進行append操做,最後經過toString方法返回String對象。也就是說這個循環執行完畢new出了10000個對象,試想一下,若是這些對象沒有被回收,會形成多大的內存資源浪費。從上面還能夠看出:string+="hello"的操做事實上會自動被JVM優化成:優化

StringBuilder str = new StringBuilder(string);

str.append("hello");

str.toString();

                       

1.1.2            StringBuilder循環累加

StringBuilder stringBuilder = new StringBuilder();

for(int i=0;i<10000;i++)

{

  stringBuilder.append("hello");

}

for循環式從13行開始到27行結束,而且new操做只進行了一次,也就是說只生成了一個對象,append操做是在原有對象的基礎上進行的。所以在循環了10000次以後,這段代碼所佔的資源要比String小得多。

 

1.1.3            StringBuffer循環累加

StringBuilder和StringBuffer類擁有的成員屬性以及成員方法基本相同,區別是StringBuffer類的成員方法前面多了一個關鍵字:synchronized,不用多說,這個關鍵字是在多線程訪問時起到安全保護做用的,也就是說StringBuffer是線程安全的。

 

1.2  性能測試

對三個類進行50000次循環累加性能測試。String 8998毫秒,StringBuilder 2毫秒,StringBuffer3毫秒。由於String須要屢次new StringBuilder,因此須要消耗大量的時間和形成大量的內存垃圾。StringBuffer和StringBuilder差很少,由於StringBuffer線程安全,因此會比StringBuilder多1毫秒。當字符串相加操做或者改動較少的狀況下,建議使用 String str="hello"這種形式;當字符串相加操做較多的狀況下,建議使用StringBuilder,若是採用了多線程,則使用StringBuffer。

1.3  練習測試

(1)下面這段代碼的輸出結果是什麼?

  String a = "hello2";   String b = "hello" + 2;   System.out.println((a == b));

  輸出結果爲:true。緣由很簡單,"hello"+2在編譯期間就已經被優化成"hello2",所以在運行期間,變量a和變量b指向的是同一個對象。

(2)下面這段代碼的輸出結果是什麼?

  String a = "hello2";    String b = "hello";       String c = b + 2;       System.out.println((a == c));

  輸出結果爲:false。因爲有符號引用的存在,因此  String c = b + 2;不會在編譯期間被優化,不會把b+2當作字面常量來處理的,所以這種方式生成的對象事實上是保存在堆上的。所以a和c指向的並非同一個對象。javap -c獲得的內容:

 

(3)下面這段代碼的輸出結果是什麼?

  String a = "hello2";     final String b = "hello";       String c = b + 2;       System.out.println((a == c));

  輸出結果爲:true。對於被final修飾的變量,會在class文件常量池中保存一個副本,也就是說不會經過鏈接而進行訪問,對final變量的訪問在編譯期間都會直接被替代爲真實的值。那麼String c = b + 2;在編譯期間就會被優化成:String c = "hello" + 2; 下圖是javap -c的內容:

  

 

總結:

對於String b=「hello」+2;這種常量相加,在編譯期就優化爲常量,在常量池保存。對於String b=a+2; 不會在編譯期間被優化,不會把b+2當作字面常量來處理的,實際是存儲在堆上面的,調用了一次new StringBuilder。

若是a的定義是final String a = "hello";     對於被final修飾的變量,會在class文件常量池中保存一個副本,也就是說不會經過鏈接而進行訪問,對final變量的訪問在編譯期間都會直接被替代爲真實的值。那麼String b= a + 2;在編譯期間就會被優化成:String b = "hello" + 2; 

String a = "hello";String b =  new String("hello");String c =  new String("hello");String d = b.intern();String.intern方法的使用。在String類中,intern方法是一個本地方法,在JAVA SE6以前,intern方法會在運行時常量池中查找是否存在內容相同的字符串,若是存在則返回指向該字符串的引用,若是不存在,則會將該字符串入池,並返回一個指向該字符串的引用。所以,a和d指向的是同一個對象。

 

 

本身編了一個股票監控軟件,有以下功能,有興趣的朋友能夠下載;

(1)   個股監測。監測個股實時變化,能夠監測個股大單交易、急速拉昇和降低、主力入場和出場、股票最高點和最低點提醒。檢測到最高點、最低點、主力進場點、主力退場點、急速拉昇點、急速下跌點,給出語音或者聲音提醒,不用再時刻看着大盤了,給你更多自由的時間;

(2)   大盤監測。監測大盤的走勢,採用上證、深證、創業三大指數的綜合指數做爲大盤走勢。並實時監測大盤的最高點和最低點、中間的轉折點。

(3)   股票推薦。還能根據歷史數據長期或短時間走勢進行分析,對股市3千多個股票進行分析對比,選出漲勢良好的股票,按照增加速度從大到小排序,推薦給你漲勢良好的股票;

下載地址:

1.0.3版本(修復大盤指數崩潰缺陷)下載地址:

連接:https://pan.baidu.com/s/1BJcTp-kdniM7VE9K5Kd3vg 提取碼:003h

更新連接:

https://www.cnblogs.com/bclshuai/p/10621613.html

相關文章
相關標籤/搜索