一.定義
先從類定義來看看:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
......
}
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
......
}
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
......
}
- 都是用final修飾,不可被繼承,即沒有子類,可以防止子類覆蓋情況的發生。
- String 實現了Comparable<String>。
- StringBuffer 和 StringBuilder 都繼承了AbstractStringBuilder類。
- 三者均實現了java.io.Serializable, CharSequence接口。
二、無參數構造函數
1. 首先,看一下String的無參構造函數源代碼:
public String() {
this.value = new char[0];
}
- 該函數創建了一個空字符序列(character sequence)對象。由於字符串是不可變的,所以該構造函數沒有必要用。
private final char value[];
- this.value = new char[0],初始化一個空char數組value。
- value是一個字符數組。
2. 然後我們看看StringBuilder()源代碼:
public StringBuilder() {
super(16);
}
super(16)是父類 AbstractStringBuilder的構造函數:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
同String一樣,value是一個字符數組:
char[] value;
StringBuilder()方法創建了一個大小16的字符數組 ,用於存儲字符。
3. 繼續看 StringBuffer():
public StringBuffer() {
super(16);
}
StringBuffer的父類也是AbstractStringBuilder,所以同StringBuilder()一樣,創建了一個大小16的字符數組。
由以上可以知道:
String()創建一個空字符數組;
而StringBuffer()和StringBuffer()創建一個大小爲16的字符數組。
String的字符數組value是final的,而StringBuffer和StringBuffer則不是。
三、帶有初始字符串的構造函數
開發中常用的,創建一個指定字符串內容的對象,代碼如下:
String s = new String("qqq");
StringBuilder sb = new StringBuilder("qqq");
StringBuffer sb1 = new StringBuffer("qqq");
1. 首先看看new String("qqq")的源代碼:
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
實際上,就是把參數original字符串對象的字符數組value和hash code直接賦值給新對象。我們已經知道value是字符數組,那麼hash是什麼呢,先看定義:
private int hash; // Default to 0
hash是字符串的哈希code,默認值是0。那麼哈希code計算將在後續說明。
2. 再看看new StringBuilder("qqq")源代碼:
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
此處,
- 第一步,初始化數組。super(str.length() + 16)是AbstractStringBuilder構造函數:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
可以看出,這裏創建的字符數組容量=參數str大小的+16。
- 第二步,賦值。append(str)定義如下:
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
賦值時候,調用了父類方法super.append(str):
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;
}
如果str參數是null,則賦值“null”;
如果str參數非null,判斷是否有足夠的空間容納str字符串,如不夠則擴容,需要最小空間是:已用字符數(count)+str的字符數。
使用str.getChars方法將字符串中的字符複製到字符數組value中。
更新已用字符數count。
3. 最後看看new StringBuffer ("qqq")源代碼:
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
StringBuffer構造方法與StringBuilder一樣,需要注意的是append方法是加了同步鎖synchronized:
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
四、字符數組value的區別
String使用字符數組value存儲字符串數據。其定義的value是有final修飾的,代表該變量不可變的,所以String對象也就是不可變的。定義代碼如下:
private final char value[];
StringBuffer與StringBuilder也使用字符數組value存儲字符串數據。value來自父類AbstractStringBuilder。Value變量是可變的。定義代碼如下:
char[] value;
五、線程安全的區別
- String,由於value是final的。一旦創建就不會再被改變了,由於存儲的字符串不會被改變。所以一定程度上能使String對象強制變得線程安全了。
- StringBuffer,對調用方法加了同步鎖synchronized,所以線程安全的。其中部分方法定義如下:
public synchronized StringBuffer append(StringBuffer sb) {
toStringCache = null;
super.append(sb);
return this;
}
@Override
synchronized StringBuffer append(AbstractStringBuilder asb) {
toStringCache = null;
super.append(asb);
return this;
}
- StringBuilder則沒有加同步鎖,所以是非線程安全的。
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}