JDK源码之StringBuilder

StringBuilder

      StringBuilder 是一个可变的字符序列。它继承于AbstractStringBuilder,实现了CharSequence接口。StringBuffer 也是继承于AbstractStringBuilder的子类;但是,StringBuilder和StringBuffer不同,前者是非线程安全的,后者是线程安全的。
StringBuilder 和 CharSequence之间的关系图如下:
请输入图片描述

StringBuilder属性

char[] value;
int count;

      可以发现StringBuilder的底层也是使用字符数组实现的。count用于表示字符数组中使用的字符个数。

StringBuilder构造方法

public StringBuilder() {
   super(16);//初始化char[]大小为16
}
父类方法:
AbstractStringBuilder(int capacity) {
   value = new char[capacity];
}

      可以发现我们使用无参构造方法创建StringBuilder时默认初始化大小为16。

public StringBuilder(int capacity) {
    super(capacity);
}

      我们也可以通过设置capacity自定义初始化大小。

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
}

      使用字符串创建StringBuilder,需要注意的是创建的StringBuilder大小是str,length()+16。

StringBuilder strb = new StringBuilder("hello");
System.out.println(strb.capacity());//21

append()方法

@Override
public StringBuilder append(Object obj) {
   return append(String.valueOf(obj));
}
public static String valueOf(Object obj) {
   return (obj == null) ? "null" : obj.toString();
}

      最终调用的都是append(String str)方法:

@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}
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;
}

      这里需要注意的是,如果传入的字符串为null,那么会调用appendNull()方法,这个方法底层会添加'n','u','l','l'四个字符。

StringBuilder strb = new StringBuilder("hello");
strb.append("world");
strb.append(new A(100));
String str2 =null;
strb.append(str2);
System.out.println(strb);//helloworld100null

ensureCapacityInternal(count + len)方法

      在调用append方法时总会使用此方法确认容量,它传入当前StringBuilder中已使用的容量(count)和待添加的String的长度(len)之和,这是StringBuilder所需要的最小容量。

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
         value = Arrays.copyOf(value,newCapacity(minimumCapacity));
    }
}

      value.length表示的是当前StringBuilder中字符数组全部容量。如果添加字符串后所需容量大于当前StringBuilder的字符数组容量,那么就需要新开辟空间。

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int newCapacity = (value.length << 1) + 2;//初步设置,newCapacity为原来空间的2倍+2(这可能会导致溢出)
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;//如果还是不够大,直接将newCapacity设置为count + len
    }
    //newCapacity <= 0说明溢出了
    //MAX_ARRAY_SIZE - newCapacity < 0说明申请的空间大于设定的最大array大小(Integer.MAX_VALUE-8)
    //如果以上两个满足一个则去执行hugeCapacity()方法
    //如果minCapacity > Integer.MAX_VALUE则抛出OutOfMemoryError异常
    //如果MIN_ARRAY_SIZE < minCapacity则设置为minCapacity,否则设置为MAX_ARRAY_SIZE
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)? hugeCapacity(minCapacity) : newCapacity;
}

      处理可以往StringBuilder中添加String和Object,还可以添加许多类型的数据,注意添加布尔类型时是添加't','r','u','e'和'f','a','l','s','e'字符。
      同时支持添加字符数组中的一部分内容。

@Override
public StringBuilder append(char[] str, int offset, int len) {
    super.append(str, offset, len);
    return this;
}

delete()方法

public AbstractStringBuilder delete(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        end = count;
    if (start > end)
        throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) {
        System.arraycopy(value, start+len, value, start, count-end);
        count -= len;
    }
    return this;
}

      有了添加,必然少不了删除。我们可以删除StringBuilder中的部分字符,我们可以发现底层就是讲end后的字符全部拷贝到了start后而已。

replace(int start,int end,String str)方法

public AbstractStringBuilder replace(int start, int end, String str) {
    if (start < 0)
       throw new StringIndexOutOfBoundsException(start);
    if (start > count)
       throw new StringIndexOutOfBoundsException("start > length()");
    if (start > end)
       throw new StringIndexOutOfBoundsException("start > end");
    if (end > count)
       end = count;
    int len = str.length();
    int newCount = count + len - (end - start);
    ensureCapacityInternal(newCount);
    System.arraycopy(value, end, value, start + len, count - end);
    str.getChars(value, start);
    count = newCount;
    return this;
}

      可以使用replace方法对StringBuilder中的部分进行替换,并且替换字符串的长度可以大于替换部位的长度。底层依旧使用数组拷贝。
      其他大部分方法都是大同小异或者使用了String类的方法,感兴趣可以自行查看。

注意length()和capacity()

      调用length()方法返回的是字符数组中字符的数目,调用capacity()方法返回的是字符数组容量,与多少字符无关。

Last modification:May 25th, 2019 at 04:39 pm
如果觉得我的文章对你有用,请随意赞赏

Leave a Comment