先看一下StringBuilder和StringBuffer的构成

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




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

两个类继承了同一个类,也实现了同样的接口,那么导致线程不安全的方法肯定在类内部自身的方法了。

再来看一下他们共同的父类

abstract class AbstractStringBuilder implements Appendable, CharSequence {

    char[] value;
    int count;
    
}

该类有两个重要的成员变量 一个是count,一个是value,count是字符个数,也就是长度。value则为具体的字符数组。

再来看一下常见的append(String str)方法

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

讲解一下这个代码,首先数组的长度在创建的时候就是固定的,想一个原先大小为5的数组 想再添加n个元素 做法是创建一个新得5+n长度的数组,先优先放原先的数组,再在数组的长度(count)处开始添加需要添加进来的元素。

String的本质就是char[] ,所以这个方法里的str.getChars()方法不难猜出是将原先字符数组和新传进来的字符数组大小相加,创建一个不小于该长度的新数组,先优先放入旧数组,再根据旧数组的长度作为索引存入新数组,在这个过程里,count有着举足轻重的作用,他标记了需要在新字符数组的哪个索引处开始添加。如果count混乱,最后的值肯定也是不准确的。所以关键点就是方法是否加锁。

 StringBuffer:
public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

StringBuilder:
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

最后来看一下String.getChars()方法来验证一下以上是否正确

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
       /*
* @param value 新加入的数组
* @param srcBegin 新加入的数组起始位置
* @param det 原先数组
* @param destPs 原先数组添加新元素的索引 也就是count
* @param length 新加入数组的加入个数
* @return 新得数组 长度为dst.count() +value.count() ,值为两部分,自身的[dst]和新加入的[value]
* int[] arr={2,3};
* int[] arr2={1,4,5};
* System.arraycopy(arr,0,arr2,1,2);
* 此时 arr2的值为[1,2,3]
* 此处没有违背数组大小的长度无法改变的准则,只是arr2指向了另一个新得数组而已。
*/

        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); 
}

 

posted on 2020-09-01 16:48  Vinlen  阅读(227)  评论(0编辑  收藏  举报