比较String、StringBuffer和StringBuilder
在Java 中一共提供了String、StringBuffer、StringBuilder 用來表示和操作字符串,對于字符串的處理我們經常在項目中可以使用的到。了解它們底層的實現可以幫我們正確的使用這三個類,當然作為面試的高頻題目,如果面試的時候如果面到了這個題目我們也就不怕了(~ . ~。 
 
一、String
首先來講String 類,可能很多人知道String 對象是內容不可變的,至于為什么是不可變的,我們通過源碼來一探究竟。String 類被final 關鍵字修飾這也意味著String 類不可以被繼承,其中實現了Serializable,Comparable,CharSequence 接口,說明String 類自身可以被序列化、并且具有排序以及其他的功能。
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence上面的信息并不能說明String 類內容是不可變的,String 底層其實是一個char 類型的數組,有關String 類的所有操作其實都是對這個數組進行操作然后進行處理的,比如下面的charAt() 方法就是根據傳入的下標返回數組中對應的字符。
/** The value is used for character storage. */private final char value[];..........public char charAt(int index) {if ((index < 0) || (index >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return value[index];}這個char 類型的數組也是被final 修飾的,因為被final 修飾的變量不可改變,這也是為什么String 類型的數據不可變。
當你定義一個String 類型的字符串時首先會檢查在內存中是否存在該String類型的數據,如果存在那么定義的這個字符串對象就會直接指向內存中的對象并返回一個引用,如果不存在,那么就在內存中開辟一塊空間用來存儲該對象,并返回一個該對象的引用。
當對字符串進行相關的操作時,如果字符串中的數據發生變化,那么都會返回一個新的字符串的引用,也就是說在內存中原來的對象并沒有被改變。
二、StringBuilder 與StringBuffer
我們把StringBuffer 與 StringBuilder 放在一起講述,這兩個類都繼承了相同的抽象類AbstractStringBuilder ,都實現了Serializable 與CharSequence 接口。
StringBuffer 與 StringBuilder 類 和String 類不同的是它們兩個都是內容可變的字符串,因為它們都實現了AbstractStringBuilder 抽象類。在AbstractStringBuilder 抽象類中也定義了一個char 類型的數組,當這兩個類進行字符串的操作時,都會改變這個字符數組,因為它不被final 修飾,所以它們不像String 對象一樣一旦被定義就不可改變。
public final class StringBufferextends AbstractStringBuilderimplements java.io.Serializable, CharSequencepublic final class StringBuilderextends AbstractStringBuilderimplements java.io.Serializable, CharSequence/*** The value is used for character storage.*/char[] value;數組的長度是不可改變的(這也是為什么數組比集合的效率要高),那么為什么StringBuffer 與 StringBuilder 的字符串卻是可以改變的呢?
我們以StringBuilder 類中的append() 為例,當StringBuilder 對象調用append() 方法時都會調用父類(AbstractStringBuilder )中的append() 方法,在AbstractStringBuilder 中進行append() 操作時都會執行ensureCapacityInternal() 方法進行內部容量擔保操作,ensureCapacityInternal() 方法中調用了expandCapacity() 擴展字符數組容量的方法。在expandCapacity() 方法中實現了對原字符數組的擴容,為了大家能夠充分理解源碼的意思我在源碼中添加了注釋。
// StringBuilder 中的append 方法@Overridepublic StringBuilder append(String str) {super.append(str);return this;}//以下是AbstractStringBuilder 中的方法public AbstractStringBuilder append(String str) {if (str == null)return appendNull();int len = str.length();// count 表示原字符數組中使用的字符數,len 表示要添加的字符的長度,相加后表示新字符串的長度ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}..............private void ensureCapacityInternal(int minimumCapacity) {// overflow-conscious code//當新字符串的長度大于原分配字符數組的長度時,調用擴展數組容量的方法if (minimumCapacity - value.length > 0)expandCapacity(minimumCapacity);}................void expandCapacity(int minimumCapacity) {int newCapacity = value.length * 2 + 2;//如果條件成立,給新字符數組的長度賦值為新字符串的長度,條件不成立時直接使用newCapacity 做為數組的長度if (newCapacity - minimumCapacity < 0)newCapacity = minimumCapacity;if (newCapacity < 0) {if (minimumCapacity < 0) // overflowthrow new OutOfMemoryError();newCapacity = Integer.MAX_VALUE;}//調用Arrays 中的方法返回指定長度的字符數組,到這里原字符數組的長度就被擴展了value = Arrays.copyOf(value, newCapacity);}我們已經結合了源碼分析了StringBuffer 與 StringBuilder 的類知道為什么這兩個類的字符串是可以被擴展的,以及擴展的過程實現。 
 一 
 那么這兩個類有什么不同呢?我們也以append() 方法為例好了。其中最大的不同就是StringBuffer 中使用的是同步的方法,它保證在并發執行的過程中能夠正確的執行,但是它同樣也存在著效率方面的問題,所以我們要正確的使用StringBuffer 與 StringBuilder 。
在這里另附一道題目:String 重載”+”,有興趣的也可以看一看。
總結
以上是生活随笔為你收集整理的比较String、StringBuffer和StringBuilder的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Java 虚拟机内存分配与回收策略
- 下一篇: 木乃以布+彝族话怎么读?
