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


一: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

 


免責聲明!

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



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