Java基礎07 String、StringBuilder、StringBuffer的區別
String 類
在Java的程式設計中,字串是運用的比較多的型別,字串是由Java的String類來建立的,需要注意的是String類被 final
修飾的類,這意味著該類不能繼承,該類的物件值是不可變的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
但在平時使用的時候,我們經常這樣操作來改變String物件變數的值
String str = "hello"; str += "world";
其實這樣的操作很消耗記憶體,浪費儲存空間,我們來看下上面的語句塊會產生哪些操作。
- 在堆上開闢一個空間用於儲存 hello
- 在棧上分配一個空間用於儲存str,儲存的值是堆記憶體的 hello 地址
- 在堆上開闢一個空間用於儲存 world.
- 拼接 hello 與 world.兩個字串,放入堆另外開闢的一個記憶體空間
- 棧上儲存str的值變為 helloworld. 的堆記憶體地址
經過上面的步驟分析,我們可以知道,String 型別的字串在進行拼接的時候,在堆記憶體上開闢了三次空間,而且只使用其中一個記憶體空間,這無疑是對堆記憶體空間的極大的浪費。
為了能解決這個問題,也就引入了 StringBuild 和 StringBuffer。
StringBuffer與StringBuilder
StringBuilder 與 StringBuffer 兩個類主要用於對字串頻繁修改的場景,它們是對 String 的優化,在追加字串的時候不會去堆上開闢新的空間,會直接在已有的堆空間追加。
上圖是String、StringBuffer、StringBuilder的層級關係圖,我們可以看出StringBuilder與StringBuffer繼承了AbstractStringBuilder抽象類,檢視原始碼可知,StringBuilder與StringBuffer最終使用的方法還是它們的父類AbstractStringBuilder中的方法,唯一不同的是StringBuffer比StringBuilder多做了一個加鎖的操作,這也就導致StringBuffer是執行緒安全的,但執行效率比較低,而StringBuilder不是執行緒安全的,但執行效率較高。
StringBuilder
public StringBuilder(String str) {
super(str.length() + 16);
append(str); // 呼叫本類的
}
@Override
public StringBuilder append(String str) { // 沒有加鎖
super.append(str); // 直接呼叫父類的追加方法
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
StringBuffer
public StringBuffer(String str) {
super(str.length() + 16);
append(str); // 呼叫本類的
}
@Override
public synchronized StringBuffer append(String str) { // 加鎖
toStringCache = null;
super.append(str); // 呼叫父類的追加方法
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
可能有些疑問,為什麼String、StringBuilder、StringBuffer三個類都是被 final 修飾,但只有String的值是不可變的呢?
其實很簡單,StringBuilder、StringBuffer確實是被 final 修飾的,而且他們本身也確實是不可變的,但我們需要注意的一點,他們追加的真正操作是在它們的父類中進行的,而它們的父類是沒有被 final 修飾,這也就間接的理解StringBuilder、StringBuffer是可變的字串,追加的時候不需要在堆記憶體開闢新的空間。
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
總結:三者的區別
- 三者都是被 final 修飾的類,但String類是不可變的,而其它兩個可以間接理解為可變的。
- StringBuilder和String不是執行緒安全的,StringBuffer是執行緒安全的。
- 效率:StringBuilder > StringBuffer。
- 在字串變數的值不經常改變的情況下(甚至不變),可以使用String,也可以使用StringBuilder;在字串變數的值經常改變且不是多執行緒環境下,使用StringBuilder;在字串變數的值經常改變且在多執行緒環境下,使用StringBuffer.