StringBuilder和StringBuffer:

    这两个类的实现原理基本相同,但StringBuffer是线程安全的,StringBuilder是非线程安全的。所以如果分析这两个类避不开AbstractStringBuilder抽象类。

           在多线程中推荐使用StringBuffer,如果在单线程情况中使用StringBuilder会更好,StringBuilder没有锁,执行速度会更快。StringBuffer和StringBuilder都比String执行速度块。


学习内容:

        StringBuffer和StringBuilder他们两都继承了AbstractStringBuilder抽象类,他们的底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用StringBuffer和 StringBuilder来进行操作。 另外StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

        String是不可变的字符串缓存区,而StringBuffer和StringBuffer是可变的字符串缓存区。


源码分析:

1.继承和接口图

StringRedisTemplate 线程安全 写法 stringbuffer线程安全原理_序列化

StringRedisTemplate 线程安全 写法 stringbuffer线程安全原理_ci_02

         StringBuilder和StringBuffer都继承了AbstractStringBuilder抽象类,在String源码分析中,String和StringBuffer或者StringBuilder比较是否相等的方法。

nonSyncContentEquals(AbstractStringBuilder sb)

2.构造方法

StringBuilder:

// StringBuilder的构造方法都是调用了父类的构造方法

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

StringBuffer: 

// StringBuffer的构造方法都是调用了父类的构造方法

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

AbstractStringBuilder类:

// 无参构造并没有被调用
    AbstractStringBuilder() {
    }    

    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

结论:StringBuffer和StringBuilder创建时都是通过其父类  AbstractStringBuilder。

        1.无参数时,每次默认都是创建长度为16的字符串缓存区。

        2.传入int capacity参数时,创建长度为capacity的字符串缓存区

        3.但当传入字符串或字符数组时,字符串缓存区长度 = 传入字符串长度+16

3.成员变量

StringBuilder:
 
 
// 序列化id(版本号) 序列化时不会进行序列化,而是复制一个进行序列化
static final long serialVersionUID = 4383685877147921099L;
 
 
StringBuffer:
 
 
// 序列化id(版本号) 序列化时不会进行序列化,而是复制一个进行序列化  static
静态变量不能被序列化,会出现错值。                                                          
static final long serialVersionUID = 3388685877147921107L;   
                         
//toStringCache用transient修饰,表示该字段不可序列化。他用于缓存toString最后一次返回的值,当修改的时候缓存会被清除。数组一旦修改,将会改变。
private transient char[] toStringCache;
 
 
//用于序列化的,序列化value,count,shared
private static final java.io.ObjectStreamField[] serialPersistentFields =
{
    new java.io.ObjectStreamField("value", char[].class),
    new java.io.ObjectStreamField("count", Integer.TYPE),
    new java.io.ObjectStreamField("shared", Boolean.TYPE),
};
 
 
AbstractStringBuilder:
 
 
// 字符数组  可变的没有用final修饰
char[] value;
 
 
// 字符数组中被占用的个数 即字符串长度
int count;
 
 
// 最大长度为Integer最大值减8  即数组最大长度为Integer最大值减8
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

 结论:

        1.StringBuffer比StringBuilder多了两个成员变量

                        toStringCache:用来提升StringBuffer的toString()输出,在数组未改变,将缓存最后一次toString的数组结果,如果数组发生了改变,将清除缓存。

                        serialPersistentFields:用于序列化的,序列化value,count,shared

        2.AbstractStringBuilder、StringBuffer、StringBuilder的数组最大上限是Integer.MAX_VALUE-8

        3.与String不同的是,StringBuilder和StringBuffer的数组都是可变的,而String是copy产生一个新的数组,内存地址不同了。

4.方法

对于方法的比较,我将对分析的方法列举三个一同看。

// 对于append方法,StringBuffer和StringBuilder使用父类的append,
    // 但是StringBuffer会在append的之前将toStringCache清空
    // StringBuffer
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }

    
    // StringBuilder
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    直接看AbstractStringBuilder

// 传字符串
    public AbstractStringBuilder append(String str) {
        if (str == null)          // 如果是null 就返回null
            return appendNull();
        int len = str.length();   // 字符串长度
        // 验证一下数组长度是否够用 (已占用的长度+字符串长度 > 数组总长度)大于执行扩容
        ensureCapacityInternal(count + len);   
        str.getChars(0, len, value, count); // 调用String的getChars 将字符串复制到value后面
        count += len;  // count = count + len 
        return this;
    }

     // 传的是对象,调用String类中valueOf(obj) 然后调用传字符串的append方法
     // String类  return (obj == null) ? "null" : obj.toString();
     public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    // 传StringBuilder 
    public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)      // 判断是否为null
            return appendNull();
        int len = sb.length();   // 字符串长度
        // 验证一下数组长度是否够用 (已占用的长度+字符串长度 > 数组总长度)大于执行扩容
        ensureCapacityInternal(count + len);
         // 调用String的getChars 将字符串复制到value后面
        sb.getChars(0, len, value, count);
        count += len;    // count = count + len 
        return this;
    }

    // 传StringBuffer 和上面一样
    AbstractStringBuilder append(AbstractStringBuilder asb) {
        if (asb == null)
            return appendNull();
        int len = asb.length();
        ensureCapacityInternal(count + len);
        asb.getChars(0, len, value, count);
        count += len;
        return this;
    }

    // 传的是CharSequence接口   char StringBuffer  StringBuilder  String 和上面一样
    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());
    }

 多个append方法都判断了传进来的对象是否为null,然后调用 appendNull()方法

// 直接存储一个null
    private AbstractStringBuilder appendNull() {
        int c = count; 
        ensureCapacityInternal(c + 4);  // 判断 已占用+4 是否超过数组长度,超过开始扩容
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
    }

在append()方法中都调用了 ensureCapacityInternal(int minimumCapacity) 方法

// 判断是否空间是否够用 不够扩容 够了就算了
    // minimumCapacity:  已占用的长度 + 需要加的长度
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) { // 不够用调取扩容方法看下面
            value = Arrays.copyOf(value,     // 只是将对象里的char重新构造了一个数组长度更大的数组
                    newCapacity(minimumCapacity));
        }
    }

    
    // 扩容算法  计算需要扩容为多大的长度   minCapacity 已占用长度 + 需要加的长度
    private int newCapacity(int minCapacity) {  
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;  // 扩容长度算法 总长度 * 2 + 2
        if (newCapacity - minCapacity < 0) {  // 判断够用不 
            newCapacity = minCapacity;   //  不够用 就扩容到传进来的长度 已占用长度 + 需要加的长度
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) // 判断是否超出最大值范围 最大为Integer.MAX_VALUE-8
            ? hugeCapacity(minCapacity)  // 超了抛出异常 没超出就返回minCapacity 相等就是MAX_ARRAY_SIZE即Integer.MAX_VALUE-8
            : newCapacity;
    }

这里其他相关的方法基本与String中的一致,不再分析了。