一 Java 中字符串的不變性
String 字符串常量,字符串長度不可變。
字符串的不變性:String 對象創建後則不能被修改,是不可變的。
你肯定在想不對吧,字符串可以重新賦值修改。下面我們就來詳細說說。
重新賦值修改字符串其實是創建了新的對象,所指向的內存空間不同。
我們來看個圖,更容易理解一點
String str1 ="Hello World"
聲明瞭一個字符串對象, str1 存放了到字符串對象的引用,在內存中的存放引用關係如下圖所示:
對str1字符串進行賦值修改
str1 ="Hello World Java"
其實質是創建了新的字符串對象,變量 str1 指向了新創建的字符串對象,如下圖所示:
下面看看 String 不變性的原因
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. *
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
用於存放字符的數組被聲明爲final的,因此只能賦值一次,不可再更改。所以可以知道String對象是不可變的。
一旦一個字符串在內存中創建,則這個字符串將不可改變。如果需要一個可以改變的字符串,我們可以使用StringBuffer或者StringBuilder。
二 StringBuffer和StringBuilder介紹
StringBuilder:字符串變量(非線程安全)。在內部,StringBuilder對象被當作是一個包含字符序列的變長數組。
StringBuffer:字符串變量(Synchronized,即線程安全)。如果要頻繁對字符串內容進行修改,出於效率考慮最好使用StringBuffer,如果想轉成String類型,可以調用StringBuffer的toString()方法。
AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,是一個抽象類定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
三 String,StringBuffer和StringBuilder區別
3.1 從可變與不可變比較
String類中用於存放字符的數組被聲明爲final的,因此只能賦值一次,不可再更改。所以可以知道String對象是不可變的。
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中用於存放字符的數組沒有被聲明爲final的。所以可以知道StringBuilder與StringBuffer對象是可變的。
3.2 是否多線程安全
String中的對象是不可變的,也就可以理解爲常量,顯然線程安全。
StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。看下源碼:
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。看下源碼:
public StringBuilder append(String str) {
super.append(str);
return this;
}
四 使用策略
- 基本原則:如果要操作少量的數據,用String ;單線程操作大量數據,用StringBuilder ;多線程操作大量數據,用StringBuffer。
- 不要使用String類的”+”來進行頻繁的拼接,因爲那樣的性能極差的,應該使用StringBuffer或StringBuilder類,這在Java的優化上是一條比較重要的原則。
- StringBuilder一般使用在方法內部來完成類似”+”功能,因爲是線程不安全的,所以用完以後可以丟棄。StringBuffer主要用在全局變量中。
- 爲了獲得更好的性能,在構造 StringBuffer 或 StringBuilder 時應儘可能指定它們的容量。當不指定容量(capacity)時默認構造一個容量爲16的對象。
- 如果程序不是多線程的,那麼使用StringBuilder效率高於StringBuffer。