StringBulider学习

1、StringBulider与“+”

1、字符串“+”实际上也是调用的StringBulider的方法
2、在字符串拼接的时候尽量使用StringBulider而不是“+”,StringBulider性能更高。
具体原因如下:

String a="a";
 a=a+"a";
 a=a+"b";

上边的代码实际相当于

String a="a";
a=new StringBulider(a).append("a").toString();
a=new StringBulider(a).append("b").toString();
public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
 }
 public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

为了数据的安全性,不破坏数据的封装,StringBulider toString方法并不会直接返回StringBulider的char数组,而是使用了保护性拷贝,拷贝一个新的char[]数组并赋给一个新的字符串。

对比之后就不难理解为什么不要使用“+”了,因为会大量new StringBulider,并大量调用toString方法,不仅效率低而且占用内存。

2、StringBulider初始长度 的重要性

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

上边的代码是StringBulider的三个构造方法,我们都知道StringBulider是把数据存储在char数组中,而StringBulider默认的数组长度是16,那么当你调用append方法时候数组长度不够会怎么处理呢

public AbstractStringBuilder append(String str) {
        if (str == null) str = "null";
        int len = str.length();

        ensureCapacityInternal(count + len);

        str.getChars(0, len, value, count);
        count += len;
        return this;
 }
private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);
 }
void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
 }

上边是append方法的处理过程,可以看到当数组长度不够的时候,先判断将长度放大两倍够不够,不够的话

if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;

使用原数组长度+要添加的字符串长度,之后使用Arrays.copyOf(value, newCapacity)方法新建数组并复制原数组。
假设要拼接的字符串长度分别为1,32,64,128会发生什么,StringBulider会不停的调用3次Arrays.copyOf(value, newCapacity)方法来拓展数组空间

public static char[] copyOf(char[] original, int newLength) {
        char[] copy = new char[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
 }

Arrays.copyOf方法并不会在原有的数组上增加长度,而是重新声明一个数组,并将原数组拷贝过去,效率低,而且浪费空间(因为原数组的空间将不被使用)。
当你将StringBulider初始化数组长度设置为64,128或者256呢,Arrays.copyOf(value, newCapacity)将会分别调用2,1,0次。
所以,合理设置一个初始值非常重要

你可能感兴趣的:(StringBulider学习)