StringBuilder && StringBuffer原理浅析

Posted xinxinblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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("
");
        stringBuilder.append("Country:").append(strCountry).append("
");

        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("
");
        stringBuffer.append("Country:").append(strCountry).append("
");

        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原理浅析的主要内容,如果未能解决你的问题,请参考以下文章

String&StringBuffer&StringBuilder

String&StringBuilder&StringBuffer

day11-StringBuilder&Math&Arrays&包装类&日期时间类

day11-StringBuilder&Math&Arrays&包装类&日期时间类

整理Java基础知识--StringBuffer&StringBuilder类

StringBuilder&StringBuffer