美文网首页Java8_131 rt包源码阅读记录
java.lang.StringBuilder、StringBu

java.lang.StringBuilder、StringBu

作者: Oliver_Li | 来源:发表于2019-12-08 17:49 被阅读0次

1. 描述:

  • StringBuilderStringBuffer都是AbstractStringBuilder的子类,String的可变方式,String不可变操作只能new一个新对象,效率不高。
  • 字符串类都使用字符数组保存,String数组的长度是固定的,这两个类可变,所以会有数组长度变化的问题。
  • StringBuilder线程不安全,StringBuffer线程安全但速度相比较慢,但拼接肯定都比String快。
  • StringBuilder、StringBuffer,主要就是append()insert()的各种重载方法对value[]进行操作。
  • 核心字段(字段在父类AbstractStringBuilder中):
    • char[] value:和String一样,StringBuilder、StringBuffer也是字符数组,但可变。
    • int count:存储value[]已有元素个数。数组总长直接调用value.length
    • private transient char[] toStringCache;:StringBuilder独有的value[]缓存,后面会具体说。

2. 构造函数(StringBuilder)

//以入参”AAAA“为例
public StringBuilder(String str) {
    //初始数组长度就是4 + 16
    super(str.length() + 16);
    //调用AbstractStringBuilder的append(str),StringBuilder和StringBuffer的父类
    append(str);
}

public AbstractStringBuilder append(String str) {
    if (str == null)
        //数组当前后添加{'n','u','l','l'}
        return appendNull();
    int len = str.length();
    //扩容
    ensureCapacityInternal(count + len);
    //利用System.arraycopy()把str补到后面
    str.getChars(0, len, value, count);
    //记录已有元素个数
    count += len;
    return this;
}

//计算扩容长度,用Arrays.copyOf()设置value[]
private void ensureCapacityInternal(int minimumCapacity) {
      if (minimumCapacity - value.length > 0) {
          value = Arrays.copyOf(value,
                  newCapacity(minimumCapacity));
      }
  }

//计算扩容后长度。minCapacity是期望长度
private int newCapacity(int minCapacity) {
    // 2*minCapacity + 2
    int newCapacity = (value.length << 1) + 2;
    //如果还不够大直接等于minCapacity
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    //边界判定最大不超过Integer.MAX_VALUE,return
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}
  • 可传入StringCharSequence、初始化容量、无参四种,除传入容量其他方式都是默认字符串长度 + 16
  • 扩容长度:原数组长度* 2 + 2,如果还是不够,直接扩容到传入的期待值minCapacity。

3. append()(StringBuilder)

  • 构造函数中介绍了append(),append()有很多重载方法,传入int、double、boolean等,最终都是转成字符拼到了value[]后面,例如"AAAA 1 1.11 false"

4. insert()(StringBuilder)

public AbstractStringBuilder insert(int offset, char c) {
      ensureCapacityInternal(count + 1);
      System.arraycopy(value, offset, value, offset + 1, count - offset);
      value[offset] = c;
      count += 1;
      return this;
  }
  • insert()append()的区别就是insert()可以指定下标插入字符串,两者源码上区别不大,都是利用System.arraycopy()做的数组拼接。

5. StringBuilder和StringBuffer

  • 前面说到两者的区别就是线程安全,除了线程优化其他几乎没有区别:
    • StringBuffer在方法上加synchronized保证线程安全。
    • StringBuffer调用toString()时并发的优化:
//-- StringBuilder.java --
public String toString() {
    return new String(value, 0, count);
}

//-- StringBuffer.java --
private transient char[] toStringCache;
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}
  • StringBuilder的toString()创建了一个新的value[],因为不适用于并发,所以没有并发优化。
  • StringBuffer的toString()把value[]提前新建并存在了toStringCache里,任何修改时都会更新toStringCache,并发量大时不会每次调用都new一个新的String。

相关文章

网友评论

    本文标题:java.lang.StringBuilder、StringBu

    本文链接:https://www.haomeiwen.com/subject/hqimgctx.html