【源码解析】Java8-StringBuild和StringBuffer

### StringBuild 和 StringBuffer
  1. 源码及分析:

    • 类定义:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence{
    public StringBuilder() {
    super(16);
    }
    public StringBuilder(int capacity) {
    super(capacity);
    }
    public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }
    public StringBuilder(CharSequence seq) {
    this(seq.length() + 16);
    append(seq);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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;
    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);
    }
    }

    从这里可以看出这两个类除了名字不一样其他都一样,其中CharSequence接口包含了charAt()、length() 、subSequence()、toString()这几个方法,String类也实现了这个接口,那么这里重点看一下AbstractStringBuilder这个类

    • AbstractStringBuilder:

      1. 成员变量及构造方法:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        abstract class AbstractStringBuilder implements Appendable, CharSequence {
        /**
        * The value is used for character storage.
        */
        char[] value;
        /**
        * The count is the number of characters used.
        */
        int count;

        /**
        * This no-arg constructor is necessary for serialization of subclasses.
        */
        AbstractStringBuilder() {
        }

        /**
        * Creates an AbstractStringBuilder of the specified capacity.
        */
        AbstractStringBuilder(int capacity) {
        value = new char[capacity];
        }
        }

        这里的char数组不是final的,在构造的时候可以指定初始容量,由他们两个的构造函数可以看到,初始化容量为默认为16,若是直接new一个字符串会在字符串容量的基础上加16,其中count为字符串使用的长度,value.length才是此时分配的长度

      2. append()方法:

        StringBulider:

        1
        2
        3
        4
        5
        @Override
        public StringBuilder append(String str) {
        super.append(str);
        return this;
        }

        StringBuffer:

        1
        2
        3
        4
        5
        public synchronized StringBuffer append(StringBuffer sb) {
        toStringCache = null;
        super.append(sb);
        return this;
        }

        可以看出这两个类都是调用了父类的append方法,其中StringBuffer不同的是加入了synchronized,所以StringBuffer是线程安全的

        来看一下父类中append方法是怎么实现的:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
        return appendNull();
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
        }

        其中有一个ensureCapacityInternal来确保新增的字符串的长度够用,代码为:

        1
        2
        3
        4
        5
        6
        7
        private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
        newCapacity(minimumCapacity));
        }
        }

        如果使用的长度加上需要添加的字符串的长度大于分配的长度就需要扩容,扩容如下:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        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;
        }
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

        新的大小为原来分配长度左移1位(*2的1次方)在加2,如果还不满足就直接为新增之后的长度,最后要是再大,看看到没到Integer的最大长度,那样的话就抛异常了

        备注:我们发现StringBuffer中好像多了一个参数—toStringCache,这个变量是用于最近一次toString()方法缓存,只要被修改这个变量就会被赋值为null