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是啥意思:

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

    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()方法了吗?上一篇博文里提到了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关键字修饰的方法包装了一层,来达到线程安全的目的!至于为什么要防止toStringCache被序列化呢?请看这里:

    @Override
    public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }

翻遍整篇StringBuffer的源码,只有这一处是给toStringCache赋值了,其他地方都是置空。不难想象,toStringCache存在的意义就是toString()的时候临时存储StringBuffer的char数组,当然不需要参与序列化了。请注意,即使此处的toString()方法,也是线程安全的!然鹅,String是非线程安全的:

    String(char[] value, boolean share) {
        // assert share : "unshared not supported";
        this.value = value;
    }

注意方法里的断言。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值