JDK源码阅读(4):StringBuffer类

AbstractStringBuilder有两个实现类,一个是StringBuilder,另一个是StringBuffer。AbstractStringBuilder要解决的是String对象不可变的问题。那么,StringBuffer和StringBuilder作为AbstractStringBuilder的实现类,区别又是什么呢?

  

     可以看出,还是很不一样的。接下来,我们要深入阅读StringBuffer类了。

public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence{

    /**
     * A cache of the last value returned by toString. Cleared
     * whenever the StringBuffer is modified.
     */
    private transient char[] toStringCache;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    static final long serialVersionUID = 3388685877147921107L;
}

  一上来,就被吓一跳呀有木有,怎么又有一个私有化的char数组?还被一个们见过的transient修饰了?带着好奇心,赶紧百度下transient是啥意思:

搜嘎,就是防止被序列化的嘛。为甚么要防止被序列化呢?我们带着这个疑惑来继续往下读。

    public StringBuffer() {
        super(16);
    }
    
    public StringBuffer(int capacity) {
        super(capacity);
    }
 
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

    public StringBuffer(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }

   请注意,重点来了,考试要考!多少次面试被问住了:请问,你知道StringBuffer默认长度多大吗?如果下次再遇到这个问题,请大声的告诉他:16!StringBuffer默认会创建一个长度为16的char数组来存储字符。而且,如果实例化StringBuffer时,如果传入的参数是String或者CharSequence,会创建一个改参数的长度加上16的char数组。我们现在来关注下append()方法:

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

    public AbstractStringBuilder append(CharSequence s) {
        if (s == null)
            return appendNull();
        if (s instanceof String)
            return this.append((String)s);
        if (s instanceof AbstractStringBuilder)
            return this.append((AbstractStringBuilder)s);

        return this.append(s, 0, s.length());
    }

    public AbstractStringBuilder append(CharSequence s, int start, int end) {
        if (s == null)
            s = "null";
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                "start " + start + ", end " + end + ", s.length() "
                + s.length());
        int len = end - start;
        ensureCapacityInternal(count + len);
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        count += len;
        return this;
    }

  看出为什么要关注append(0方法了吗?上一篇博文里提到了ensureCapacity()系列的方法,用处就在这里。保证了StringBuffer的空间长度是最小的。好了,这一部分的介绍告一段落了,接下来该放大招了。啥大招呢?先上源码:

    @Override
    public synchronized int length() {
        return count;
    }

    @Override
    public synchronized int capacity() {
        return value.length;
    }

    @Override
    public synchronized void ensureCapacity(int minimumCapacity) {
        super.ensureCapacity(minimumCapacity);
    }
 
     @Override
    public synchronized void trimToSize() {
        super.trimToSize();
    }
 
    @Override
    public synchronized void setLength(int newLength) {
        toStringCache = null;
        super.setLength(newLength);
    }
    
    ....略....

  相信,信息的你已经发现了什么。原来,这就是StringBuffer线程安全的奥秘啊!StringBuffer几乎重写了AbstractStringBuilder类的所有方法,用synchronized关键字修饰的方法包装了一层,来达到线程安全的目的!

猜你喜欢

转载自blog.csdn.net/qq_28802119/article/details/89147310