大多數狀況下, StringBuffer 的速度要比 String 快; StringBuilder 要比StringBuffer快;StringBuffer 和 StringBuilder 都是 AbstractStringBuilder 的子類,區別在於StringBuffer 的方法大部分都有 synchronized 修飾。java
/** * 用來存儲字符的數組 * The value is used for character storage. */ char[] value; /** * 字符個數 * The count is the number of characters used. */ int count; /** * This no-arg constructor is necessary for serialization of subclasses. */ AbstractStringBuilder() { } /** * 在構造方法中指定字符數組的長度 * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { value = new char[capacity]; }
public void ensureCapacity(int minimumCapacity) { if (minimumCapacity > 0) ensureCapacityInternal(minimumCapacity); } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; } private int hugeCapacity(int minCapacity) { if (Integer.MAX_VALUE - minCapacity < 0) { // overflow throw new OutOfMemoryError(); } return (minCapacity > MAX_ARRAY_SIZE) ? minCapacity : MAX_ARRAY_SIZE; }
擴容的方法最終由 newCapacity()
實現的,首先將容量左移一位(即擴大2倍)同時加2,若是此時任小於指定的容量,那麼就將容量設置爲 minimumCapacity
。而後判斷是否溢出,經過 hugeCapacity
實現,若是溢出了(長度大於 Integer.MAX_VALUE
),則拋錯( OutOfMemoryError
);不然根據 minCapacity
和 Integer.MAX_VALUE - 8
的大小比較肯定數組容量爲 max(minCapacity, Integer.MAX_VALUE - 8)
。最後將 value
值進行拷貝,這一步顯然是最耗時的操做。c++
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; }
append()
是最經常使用的方法,它有不少形式的重載。上面是最經常使用的一種,用於追加字符串。若是 str
是 null
,則直接調用
appendNull()
方法。這個方法就是直接追加 'n'
、 'u'
、'l'
、'l'
這幾個字符,方法以下:git
private AbstractStringBuilder appendNull() { int c = count; ensureCapacityInternal(c + 4); final char[] value = this.value; value[c++] = 'n'; value[c++] = 'u'; value[c++] = 'l'; value[c++] = 'l'; count = c; return this; }
若是不是null
,則首先須要判斷數組容量是否足夠,不夠則須要擴容(擴容則是調用上述分析的擴容方法);
而後調用 String
的 getChars()
方法將 str
追加到 value
末尾;
最後返回對象自己,因此 append()
能夠連續調用(就是一種相似於鏈式編程)。github
Java
開發者認爲咱們在 append
數據的時候,中間常常會加一個分隔符,剛好這個分隔符在 Java
中正好佔用兩個字節。也不知道分析的對不對,有其餘意見的大佬們能夠在 issue經過查看源碼分析發現二者都繼承至 AbstractStringBuilder
。 而 StringBuffer
之因此是線程安全的,是由於重寫 AbstractStringBuilder
的方法的時候在前面加上了 synchronzied
修飾這些方法;而 StringBuilder
重寫的時候只是直接調用父類的方法,沒有作其餘的操做。編程
其實經過閱讀源碼發現 StringBuilder
和 StringBuffer
之間的關係,相似於 HashMap
和 HashTable
之間的關係。數組