「OpenJdk-11 源码-系列」AbstractStringBuilder,StringBuilder,StringBuffer

AbstractStringBuilder

AbstracStringBuilderStringBuilderStringBuffer 的父类。前面咱们讲到String是一个不可变的字符串。而StringBuilderStringBuffer 则是对String的一个补充,它们是可变的。先来看AbstractStringBuilder的定义java

定义

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value;
	int count;
	AbstractStringBuilder() {
	}
	AbstractStringBuilder(int capacity) {
    	value = new char[capacity];
	}
}
复制代码

从类名上就能够看出来它是一个抽象方法。而且实现了Appendable以及Appendable接口中的append方法。使用了char[]来保存值,而两个构造函数也是子类所必需要实现的,用于初始化 char[]的大小。安全

扩容

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 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;
    } 
复制代码

对于扩容,须要确保传入的capacity大于目前的value的长度,且小于Integer.MAX_VALUE(0x7fffffff)。在这个方法中首先把容量扩大为原来的容量乘2加2,若是此时仍小于指定的容量,那么就把新的容量设为minCapacity。而后判断是否溢出,若是溢出了,把容量设为MAX_ARRAY_SIZE(Integer.MAX_VALUE-8)app

添加

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;
    }	

	//String.class
	public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }
复制代码

对于 append 方法有不少重载。对于每种重载方法的内部实现大概能够分为下面几步:函数

  1. 确保 append的值为有效的。若是是字符串,那么值若是为 null,则会append一个null字符串,若是是longint的值是小于最小值,那么会append一个固定值
  2. 扩容当前值。ensureCapacityInternal方法会将当前的char[] value值复制到一个新的char[] value中。
  3. 使用 getChars方法将append的值追加到扩容的value

StringBuilder & StringBuffer

StringBuilder & StringBuffer都实现了 AbstractStringBuilder接口。他们最大的不一样就是StringBuilder 是线程不安全的,而StringBuffer是线程安全的。因此它们的属性和方法大体都是同样的,只是StringBuffer的部分方法上添加了Synchronized关键字来保证线程的安全。性能

//StringBuffer.class
	public synchronized StringBuffer append(String str) { 
        toStringCache = null;
        super.append(str);
        return this;
    }
复制代码

StringBuilder 中没有synchronized这个关键字。对于StringBuilder & StringBuffer的大部分都是调用的父类的方法,只是最后多了一个 return thisui

上面的代码咱们发现有这么一行代码toStringCache=null,咱们来看看它的定义this

/** * A cache of the last value returned by toString. Cleared * whenever the StringBuffer is modified. */
    private transient String toStringCache;
复制代码

根据注释,咱们能够知道这个toStringCache是用来缓冲最后一次 toString 的值,若是StringBuffer被修改了的话,那么toStringCache就会被清空。接着再来看看 toString方法spa

public synchronized String toString() {
        if (toStringCache == null) {
            return toStringCache =
                    isLatin1() ? StringLatin1.newString(value, 0, count)
                               : StringUTF16.newString(value, 0, count);
        }
        return new String(toStringCache);
    }
复制代码

当调用toString方法的时候,若是toStringCachenull的话,那么就会调用StringXXX.newString方法。若是不为null的话,直接返回toStringCache。而StringXXX.newString的实现以下:线程

public static String newString(byte[] val, int index, int len) {
        return new String(Arrays.copyOfRange(val, index, index + len),
                          LATIN1);
    }
复制代码

能够发现它实际上是一个copy的操做。也就是说若是toStringCache 存在的话,就不须要再次进行copy。直接返回toStringCache,这样就能够减小没必要要的消耗,提高性能。code

相关文章
相关标签/搜索