JDK源码阅读(3):AbstractStringBuilder、StringBuffer、StringBuilder类阅读笔记

AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence{
    ...
}

1. inflate方法

inflate()方法可以将当前的Latin1编码的字符串膨胀到16位,即UTF16编码(Latin1编码为8位)

/**
 * If the coder is "isLatin1", this inflates the internal 8-bit storage
 * to 16-bit <hi=0, low> pair storage.
*/
private void inflate() {
    if (!isLatin1()) {
        return;
    }
    byte[] buf = StringUTF16.newBytesFor(value.length);
    StringLatin1.inflate(value, 0, buf, 0, count);
    this.value = buf;
    this.coder = UTF16;
}

2. ensureCapacity方法

public void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > 0) {
        ensureCapacityInternal(minimumCapacity);
    }
}

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    int oldCapacity = value.length >> coder;
    if (minimumCapacity - oldCapacity > 0) {
        // 拷贝过去
        value = Arrays.copyOf(value, newCapacity(minimumCapacity) << coder);
    }
}

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = value.length >> coder;
    int newCapacity = (oldCapacity << 1) + 2;
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
    return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

ensureCapacity(miniCapacity)方法保证当前容器的大小不小于miniCapacity,如果小于的话就要进行扩容处理。扩容成下面两者中的较大值。

  • miniCapacity
  • 2*oldCapacity

3. setCharAt方法

setCharAt()方法可以将index处的字符设为ch

public void setCharAt(int index, char ch) {
    checkIndex(index, count);
    if (isLatin1() && StringLatin1.canEncode(ch)) {
        value[index] = (byte)ch;
    } else {
        if (isLatin1()) {
            inflate();
        }
        StringUTF16.putCharSB(value, index, ch);
    }
}

4. append方法

append()方法根据参数类型不同,在字符串后面追加。

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

值得一提的是这个appendNull()方法,当我们在试图append一个空对象时,它居然选择在builder串后面加上一个“null”,看下面的示例。

public static void main(String[] args) {
    StringBuilder stringBuilder = new StringBuilder("a");
    String s = null;
    stringBuilder.append(s);
    System.out.println(stringBuilder.toString());
    System.out.println(stringBuilder.toString().length());
}

输出结果居然是

anull
5

也就是说,当append空对象时,会append一个“null”字符串。

另外,当我们尝试append一个boolean对象时,会append一个“true”串或者“false”串。

5. delete方法

delete方法删除builder中的一段

public AbstractStringBuilder delete(int start, int end) {
    int count = this.count;
    if (end > count) {
        end = count;
    }
    checkRangeSIOOBE(start, end, count);
    int len = end - start;
    if (len > 0) {
        shift(end, -len);
        this.count = count - len;
    }
    return this;
}

类似地还有deleteCharAt

public AbstractStringBuilder deleteCharAt(int index) {
    checkIndex(index, count);
    shift(index + 1, -1);
    count--;
    return this;
}

6. reverse方法

reverse()方法可以逆转字符的顺序。

public AbstractStringBuilder reverse() {
    byte[] val = this.value;
    int count = this.count;
    int coder = this.coder;
    int n = count - 1;
    if (COMPACT_STRINGS && coder == LATIN1) {
        for (int j = (n-1) >> 1; j >= 0; j--) {
            int k = n - j;
            byte cj = val[j];
            val[j] = val[k];
            val[k] = cj;
        }
    } else {
        StringUTF16.reverse(val, count);
    }
    return this;
}

实际的方法就是双指针靠拢+交换、

StringBuffer

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{

StringBuffer类几乎所有方法都是通过super关键字调用AbstractStringBuilder父类的方法。

StringBuffer实现同步的方式就是给所有方法加上synchronized关键字。

1. toStringCache变量

/**
   * A cache of the last value returned by toString. Cleared
   * whenever the StringBuffer is modified.
*/
private transient String toStringCache;

toStringCache缓存了toString()方法的最后一次调用的值,在每次StringBuffer被修改前这个缓存会清除。

toString()方法中检查如果有缓存,就直接返回缓存。这样不用每次都处理toString()的过程,而只在需要的时候处理。

public synchronized String toString() {
    if (toStringCache == null) {
        return toStringCache =
            isLatin1() ? StringLatin1.newString(value, 0, count)
            : StringUTF16.newString(value, 0, count);
    }
    return new String(toStringCache);
}

StringBuilder

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

StringBuilder类几乎所有方法都是通过super关键字调用AbstractStringBuilder父类的方法。

posted @ 2021-10-09 22:27  pedro7  阅读(101)  评论(0编辑  收藏  举报