【1】String,StringBuffer,StringBuillder的底層結構研究

Love Lenka發表於2017-02-08

一:StringBuffer的底層

(1)執行緒安全的字串操作類

(2)透過synchronized關鍵字宣告同步方法,保證多執行緒環境下資料安全

1 @Override
2     public synchronized StringBuffer append(String str) {
3         toStringCache = null;
4         super.append(str);
5         return this;
6     }
View Code

(3)底層儲存資料的Char[]陣列,初始化時,該陣列的長度是16。如果建構函式有新傳入字元轉str,則16基礎上加str.length.

 1 /**
 2 *無參構造
 3 */
 4 public StringBuffer() {
 5         super(16);
 6 }
 7 
 8 
 9 
10 /**
11 *帶參構造
12 */ 
13 public StringBuffer(String str) {
14         super(str.length() + 16);
15         append(str);
16     }
17 
18 /**
19 *初始化char[]陣列
20 */
21    AbstractStringBuilder(int capacity) {
22         value = new char[capacity];
23     }
View Code

 (4)新增字串的過程

-->先檢查內部char[]陣列是否需要擴容

-->如需要擴容則進行擴容,然後將原來後設資料copy到新陣列中。

-->再將新新增的後設資料加入到新char[]陣列中

 1 public AbstractStringBuilder append(String str) {
 2         if (str == null)
 3             return appendNull();
 4         int len = str.length();
 5         //檢查char[]陣列是否需要擴容,擴容,並將原來的資料copy進去新擴容的陣列中
 6         ensureCapacityInternal(count + len);
 7         //將新新增的資料新增到StringBuilder中的char[]陣列中,實現字串的新增
 8         str.getChars(0, len, value, count);
 9         count += len;
10         return this;
11     }
12 
13 
14 /**
15 *元陣列char[]的擴容過程
16 */
17     void expandCapacity(int minimumCapacity) {
18         int newCapacity = value.length * 2 + 2;
19         if (newCapacity - minimumCapacity < 0)
20             newCapacity = minimumCapacity;
21         if (newCapacity < 0) {
22             if (minimumCapacity < 0) // overflow
23                 throw new OutOfMemoryError();
24             newCapacity = Integer.MAX_VALUE;
25         }
26         value = Arrays.copyOf(value, newCapacity);
27     }
28 
29 
30 /**
31 *擴容實現
32 */
33    public static char[] copyOf(char[] original, int newLength) {
34         char[] copy = new char[newLength];
35         System.arraycopy(original, 0, copy, 0,
36                          Math.min(original.length, newLength));
37         return copy;
38     }
View Code

 

 

二:StringBuillder的底層

 (1)執行緒非安全的字串操作類

 (2)字串的新增沒有加同步處理,涉及到陣列擴容,容易產生髒資料,破壞資料正確性

 (3)底層結構和StringBuffer實現基本一樣,只是沒有做同步處理。

--->StringBuffer和StringBuillder都繼承抽象類AbstractStringBuilder,該抽象類實現了字串操作的方法。

--->StringBuffer和StringBuillder的實現,運用了模板方法的設計模式,將核心資料操作放在父類方法裡,子類實現自己的獨有特色的功能,涉及核心操作,呼叫父類方法。

 

三:String的底層

 

String類沒有提供用於修改字串的方法。String類物件為不可變字串,如字串string=”HELLO”永遠只包含HELLO這幾個字母,而不能修改其中任何一個字元。當然可以修改字串變數string的引用,讓它引用另一個字串。
不可變字串有一個優點:編譯器可以讓字串實現共享。實際上只有字串常量(使用“ ”宣告,儲存在字串常量池中)是共享的,subStrng,+等操作產生的結果不能共享。
比較字串值是否相等時使用equals()方法,不能使用==,==比較的是字串的地址是否相同。如果字串在常量池中,可以使用==比較,因為指向的都是同一個字串。

直接使用 ” ” 宣告的String物件會直接儲存在常量池中,(可以實現共享)
1.String str1=”first”;
jvm在執行時先查詢常量池中是否有該字串,如果有則直接返回該字串的引用給first(實現了字串 的共享) ;否則先在常量
池中建立該字串並返回引用。
此時只會在常量池中建立String物件,不會在堆中建立。
2.String str2=new String(“second”);
該程式碼生成了兩個String物件。因為使用了“”會現在常量池中查詢是否存在second物件,沒有則建立
否則不建立;在常量池建立完成後,由於使用了new,jvm會在堆中建立內容相同的String物件,並將引用
返回給str2.
3.String str3=”what”; String str4=str3+”a nice day”;
執行時,+ 相當於new,所以堆中會有“what a nice day”物件;常量池中會有”what” “a nice day”兩個物件,而不會有”what a nice day”物件。

4.三者在執行速度方面的比較:StringBuilder >  StringBuffer  >  String

5.測試類

 1 package com.yeepay.sxf.mianshi.pagkage;
 2 
 3 public class StringBufferAndStringBuillder {
 4 
 5     public static void main(String[] args) {
 6 //        String a="abc";
 7 //        String b=new String(a);
 8 //        //【true】a和b比較的是內容。便利各自的char[]陣列進行比較
 9 //        System.out.println("a和b比較==>"+a.equals(b));
10 //        //【false】 a和b比較的是地址。a在常量池中  b在堆記憶體中
11 //        System.out.println("a和b比較==>"+a==b);
12         
13         test02();
14         
15     }
16     
17     
18     public static void test01(){
19         /**
20          * 你會很驚訝的發現,生成str物件的速度簡直太快了,而這個時候StringBuffer居然速度上根本一點都不佔優勢。其實這是JVM的一個把戲,實際上:
21             String str = “This is only a” + “ simple” + “test”;
22             
23             其實就是:
24             String str = “This is only a simple test”;
25             
26             所以不需要太多的時間了。但大家這裡要注意的是,如果你的字串是來自另外的String物件的話,速度就沒那麼快了,譬如:
27             
28              String str2 = “This is only a”;
29 
30     String str3 = “ simple”;
31 
32     String str4 = “ test”;
33 
34     String str1 = str2 +str3 + str4;
35 
36     這時候JVM會規規矩矩的按照原來的方式去做。
37          */
38     }
39     
40     
41     public static void test02(){
42          //string3指向常量池中的字串second
43          //string4指向堆中的字串second
44          //所以值相同,引用不同
45          String string3="second";
46          String string4=new String("second");
47          System.out.println(string3==string4);
48         System.out.println(string3.equals(string4));
49 
50          //string5指向常量池中的字串third
51          //string6一開始指向堆中的字串third,但是呼叫intern()方法之後,且該方法呼叫時先檢查常量池中是否有值為string6
52          //的字串,如果有則返回該字串的引用,否則在常量池中建立該字串,並返回引用
53          //所以一開始引用不相等,後來相等
54          String string5="third";
55          String string6=new String("third");
56          System.out.println(string5==string6);
57          string6=string6.intern();
58          System.out.println(string5==string6);
59     }
60 }
View Code

 

相關文章