天天看點

Java源碼學習 -- java.lang.StringBuilder,java.lang.StringBuffer,java.lang.AbstractStringBuilderjava.lang.StringBuilderjava.lang.StringBufferjava.lang.AbstractStringBuilder總結

一直以來,都是看到網上說“ StringBuilder是線程不安全的,但運作效率高;StringBuffer 是線程安全的,但運作效率低”,然後默默記住:一個是線程安全、一個線程不安全,但對内在原因并不了解。這兩天終于下定決心看了下源代碼,才深刻了解為啥一個線程安全、一個非線程安全。

一名話總結:java.lang.StringBuilder 與 java.lang.StringBuffer 同是繼承于 java.lang.AbstractStringBuilder,具體在功能實作大多在 AbstractStringBuilder 中,StringBuilder 和 StringBuffer 相當于對其進行的一個接口封裝,差別隻是一個作了同步封裝、一個作非同步封裝。

由表及裡,首先從 StringBuilder 和 StringBuffer 源代碼中的構造方法和 append,delete,replace,insert,toString 等方法研究起。

StringBuilder 是一個 final 類,不能被繼承。其類繼承父類和實作的接口關系如下所示:

其内部代碼中顯式聲明(不包括繼承等隐式屬性)的隻有一個屬性:serialVersionUID(序列化ID)。其構造方法的内部實作也是通過 super 方法調用父類構造方法實作,具體如下所示:

僅以一個 append 方法為例具體看看其内部實作,代碼如下:

在該方法内部仍然是一個 super 方法,調用父類在方法實作,隻是做了一層外殼。其它的 delete,replace,insert 方法源代碼也是如此,這裡就不一一展示了。相關的 append 重載方法源碼如下所示:

與 append,delete,replace,insert等方法不同的是,toString 方法不是通過 super 方法調用父類的實作。但其實作中所用到的 value,count 屬性依然是從父類中繼承的,其實作仍然很簡單,如下所示:

當認識了 java.lang.StringBuilder 後,再來學習 StringBuffer 就相當簡單了。其類聲明和構造方法與 StringBuilder 完全一樣。各功能方法内部實作上也完全一樣,具體實作調用 super 方法通過父類實作。唯一的不同之處便是:功能方法前面多了一個同步關鍵字 synchronized。這裡隻簡單給出其部分源代碼,以供參考。

類聲明和構造方法源碼如下:

append 功能方法源碼如下:

StringBuilder,StringBuffer 均是繼承于 AbstractStringBuilder ,而其方法具體實作均是調用父類的方法完成。則從功能實作上,AbstractStringBuilder 是核心。下面來研究其源碼實作。

與 java.lang.String 類似,其底層仍是通過字元數組實作字元串的存儲。不同的是多了一個 count 參數,以用于記錄實際存儲的字元個數,而不是字元數組 value 的長度。類聲明、屬性及構造方法源碼如下:

與 java.lang.String 相比,同是字元數組存儲字元串,但 String 中聲明的字元數組是 final 類型表示不可修改,而 AbstractStringBuilder 中則可以修改,這也就是為啥 StringBuilder、StringBuffer可實作字元串修改功能了。下面來看部分常用方法的具體實作。

append 的重構方法比較多,但原理是類似的。功能都是将字元串、字元數組等添加到原字元串中,并傳回新的字元串 AbstractStringBuilder。步驟如下:(1)對傳入形參正确性進行檢查;(2)對原字元數組長度進行檢查,判斷是否能容納新加入的字元;(3)對原字元數組進行相應添加操作。

以形參為 String 在 append 方法源碼為例。

其中 ensureCapacityInternal 方法用于判斷字元數組長度是否足夠,如下所示:

當字元數組長度不夠時,便建立一個新的數組,将原數組中資料拷貝到新數組中,具體拷貝方法由 Arrays.copyOf 方法實作,而 Arrays.copyOf 方法又是通過 System.arraycopy 來實作數組拷貝,該 System 方法為 native 方法。

新的數組長度取決于原數組長度和待添加的數組長度,如下所示:

研究這段源碼可以發現:如果可以提前預估出最終的數組長度并在建立對象時提前設定數組大小,對程式運作效率的提高是十分有幫助的。(減少了不斷擴容、拷貝的内在及時間成本)

append 相當重載方法源碼如下:

這三個方法的實作原理相似。

delete:可實作删除指定數組起始、終止位置之間的字元。将指定終止位置之後的字元依次向前移動 len 個字元,将起始位置的字元開始依次覆寫掉,相當于字元數組拷貝。

replace:字元數組拷貝。

insert:在數組指定位置插入字元,底層也是字元數組拷貝。

其源碼如下:

該方法是此抽象類中唯一一個抽象方法,功能就不多說了。

java.lang.StringBuilder 和 java.lang.StringBuffer 隻是對 java.lang.AbstractStringBuilder 的一個繼承封裝,通過繼承可以實作功能的一個拓展。StringBuilder僅僅隻是功能的繼承;StirngBuffer在功能繼承上做了一個synchronized加鎖的操作,進而實作線程安全性。

AbstractStringBuilder 才是功能方法的具體實作。同 java.lang.String 一樣,底層是用字元數組在存儲字元串,但差別是 String 中字元數組是 final 類型,而 AbstractStringBuilder 中字元數組是可變的。

StringBuilder 與 StringBuffer 均是 final 類,無法再被繼承。