1. 程式人生 > >StringBuilder && StringBuffer原理淺析

StringBuilder && StringBuffer原理淺析

== xtend pen 容量 clas [] 大小 直接 div

本文主要以簡單的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原理淺析