StringBuilder && StringBuffer原理淺析
本文主要以簡單的String/StringBuilder/StringBuffer操作來看這三個類的實現原理。
什麽簡單操作呢?那就是StringBuilder與StringBuffer的append() && toString()兩個方法。
示例代碼如下:
public class TestStringBuffer_Builder { public static void main(String[] args) { TestStringBuffer_Builder testStringBuffer_builder = new TestStringBuffer_Builder(); testStringBuffer_builder.testStringBuilder(); testStringBuffer_builder.testStringBuffer(); } public void testStringBuilder() { String strName = new String("JackMa"); String strCountry = new String("China"); StringBuilder stringBuilder = new StringBuilder(64); stringBuilder.append("Name:").append(strName).append("\n"); stringBuilder.append("Country:").append(strCountry).append("\n"); System.out.print(stringBuilder.toString()); } private void testStringBuffer() { String strName = new String("JackMa"); String strCountry = new String("China"); StringBuffer stringBuffer = new StringBuffer(64); stringBuffer.append("Name:").append(strName).append("\n"); stringBuffer.append("Country:").append(strCountry).append("\n"); System.out.print(stringBuffer.toString()); } }
以上的demo中,涉及到了String的構造,StringBuilder & StringBuffer的構造、append與toString。我們分別研究這幾個方法,來了解其內部的實現原理。
一、String
代碼中首先構造了String。
先簡單看看String內部發生了什麽:
public final class String { private final char value[]; private int hash; public String() { this.value = "".value; } public String(String original) { this.value = original.value; this.hash = original.hash; } public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); } }
可以看的出來,String中的數據都是保存在數組char value[]中。
對於String的concat(拼接)過程可以看出,最後生成了一個新的String對象作為拼接的結果。
二、StringBuilder
先看看StringBuilder中的方法:
public class StringBuilder extends AbstractStringBuilder { public StringBuilder(int capacity) { super(capacity); } public StringBuilder append(String str) { super.append(str); return this; } } 父類: public abstract class AbstractStringBuilder { char[] value; AbstractStringBuilder(int capacity) { value = new char[capacity]; } 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; } 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; if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); } public String toString() { // Create a copy, don‘t share the array return new String(value, 0, count); } }
StringBuilder中也是用數組進行數據保存。相比於String的concat操作,StringBuilder在拼接字符串的過程始終是一個對象在操作,變化的是StringBuilder內部的數組若容量不夠,則進行擴充。
擴容算法中,在拼接字符串不長的情況下,容量通常擴為2倍。若2倍不足,則擴為需要的大小。
在toString方法中,使用StringBuilder內部的value數組構造一個新的的String對象,並返回。
三、StringBuffer
public final class StringBuffer extends AbstractStringBuilder { private transient char[] toStringCache; public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); } }
StringBuffer中,也是用數組進行字符串數據保存。不同於StringBuilder,StringBuffer中的操作字符串方法是同步的,因此屬於線程安全類。
同時用了transient char[] toStringCache來緩存數據。在調用toString時,將字符串內容保存進toStringCache, 且在修改StringBuffer時(例如append、insert、delete等字符操作),清空該緩存。
若字符串無修改,在第二次調用toString時直接將緩存內容返回,從而提升字符轉換效率。
這裏面涉及到一個點:用於緩存字符內容的數組toStringCache是用transient修飾,直接訪問內存,從而實現線程間的可見性。具體內容可進一步了解關鍵字transient。
StringBuilder && StringBuffer原理淺析