AbstractStringBuilder源码分析

抽象类AbstractStringBuilder实现了接口AppendableCharSequence,接口Appendable中有三个重载的append方法,专门来处理字符串的添加操作。

Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;

AbstractStringBuilder中有两个重要的字段,value[]count。value是用来字符存储的,count记录value实际使用的字符数。比如value = new char[100],将’a’、‘b’、'c’放入value中,此时count=3。

char[] value;
int count;

对应的,AbstractStringBuilder中有两个方法分别来获取value的长度和实际使用的长度count,value的长度其实就是容量。getValue方法可以获取value[],此方法被final修饰,不可被子类重写。

@Override
public int length() {
    return count;
}

public int capacity() {
    return value.length;
}

final char[] getValue() {
    return value;
}

AbstractStringBuilder有两个构造方法,其中无参构造方法是为了子类的序列化,有参构造传入了一个整数来构造一个指定容量的字符数组,并赋值给value。

AbstractStringBuilder() {
}

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

接下来就是对容量的操作。

ensureCapacity方法确保value的容量至少是指定容量,如果指定容量大小比value原来的容量大小大就重新创建一个数组赋值给value。此方法在append方法的操作中很重要。

新数组的容量由newCapacity方法确定,首先扩容至原容量的2倍加2,这样扩容可能是因为如果通过有参构造方法构造一个容量为0的字符串,那么仅仅乘以2容量永远都为0。如果扩容2倍加2还是达不到指定的容量,那么就直接扩容至指定的容量,否则的话就是继续用该容量。

但此时就需要考虑该容量是否超出了int值的范围,是否超出了数组的最大容量。int数值溢出会变为负数,数组的最大容量是Integer的最大值减8,减8是因为数组需要存储一些额外的头信息,并且这些信息需要的容量不会超过8。

如果新容量超出int值范围或者超出数组最大容量,就在指定容量和数组最大容量中选择最大的作为新数组的容量。

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

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

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private int newCapacity(int minCapacity) {
    int newCapacity = (value.length << 1) + 2;
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

private int hugeCapacity(int minCapacity) {
    if (Integer.MAX_VALUE - minCapacity < 0) { 
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE)
        ? minCapacity : MAX_ARRAY_SIZE;
}

trimToSize()方法是将字符串的容量降为已被使用的容量大小。

public void trimToSize() {
    if (count < value.length) {
        value = Arrays.copyOf(value, count);
    }
}

容量可以被改变,字符串的长度也可以被改变,调用Array的fill方法填充数组并将count值设为新的长度。但要保证新的长度合法。

public void setLength(int newLength) {
    if (newLength < 0)
        throw new StringIndexOutOfBoundsException(newLength);
    ensureCapacityInternal(newLength);

    if (count < newLength) {
        Arrays.fill(value, count, newLength, '\0');
    }

    count = newLength;
}

然后就是对字符进行操作的方法,charAt方法是重写CharSequence的方法。

public char charAt(int index)public int codePointAt(int index)public int codePointBefore(int index)public int codePointCount(int beginIndex, int endIndex)public int offsetByCodePoints(int index, int codePointOffset)public void setCharAt(int index, char ch)

getChars方法可以将调用该方法的字符串复制到指定的字符数组中,将value的[srcBegin, srcEnd)复制到ts数组的[dstBegin, dstBegin+value.length)中。

public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
    if (srcBegin < 0)
        throw new StringIndexOutOfBoundsException(srcBegin);
    if ((srcEnd < 0) || (srcEnd > count))
        throw new StringIndexOutOfBoundsException(srcEnd);
    if (srcBegin > srcEnd)
        throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

接下来是一系列的append方法,在字符串后面添加字符串。其中appendNull就是在字符串后面添加"null",append(boolean b)就是在字符串后面添加"true"或"false",append(int i)就是在字符串后面添加i的字符串。

public AbstractStringBuilder append(Object obj);
public AbstractStringBuilder append(String str);
public AbstractStringBuilder append(StringBuffer sb);
AbstractStringBuilder append(AbstractStringBuilder asb);
public AbstractStringBuilder append(CharSequence s);
private AbstractStringBuilder appendNull();
public AbstractStringBuilder append(CharSequence s, int start, int end);
public AbstractStringBuilder append(char[] str);
public AbstractStringBuilder append(char str[], int offset, int len);
public AbstractStringBuilder append(boolean b);
public AbstractStringBuilder append(char c);
public AbstractStringBuilder append(int i);
public AbstractStringBuilder append(long l);
public AbstractStringBuilder append(float f);
public AbstractStringBuilder append(double d);
public AbstractStringBuilder appendCodePoint(int codePoint);

还有在字符串中间插入字符串的insert方法。核心就是首先进行扩容,然后将value指定位置之后的字符向后移动给被插入的字符串空出位置,最后插入字符串。

public AbstractStringBuilder insert(int index, char[] str, int offset, int len);
public AbstractStringBuilder insert(int offset, Object obj);
public AbstractStringBuilder insert(int offset, String str);
public AbstractStringBuilder insert(int offset, char[] str);
public AbstractStringBuilder insert(int dstOffset, CharSequence s);
public AbstractStringBuilder insert(int dstOffset, CharSequence s, int start, int end);
public AbstractStringBuilder insert(int offset, boolean b);
public AbstractStringBuilder insert(int offset, char c);
public AbstractStringBuilder insert(int offset, int i);
public AbstractStringBuilder insert(int offset, long l);
public AbstractStringBuilder insert(int offset, float f);
public AbstractStringBuilder insert(int offset, double d);

delete方法可以删除字符串的子串。

public AbstractStringBuilder delete(int start, int end);
public AbstractStringBuilder deleteCharAt(int index);

replace方法替换字符串的子串。

public AbstractStringBuilder replace(int start, int end, String str);

substring方法返回字符串的子串。

public String substring(int start);
public CharSequence subSequence(int start, int end);
public String substring(int start, int end);

indexOf方法返回子串在字符串中的位置。

public int indexOf(String str);
public int indexOf(String str, int fromIndex);
public int lastIndexOf(String str);
public int lastIndexOf(String str, int fromIndex);

resverse方法将字符串反转,以后可以借鉴该方法的实现,从中间开始

public AbstractStringBuilder reverse() {
    boolean hasSurrogates = false;
    int n = count - 1;
    for (int j = (n-1) >> 1; j >= 0; j--) {
        int k = n - j;
        char cj = value[j];
        char ck = value[k];
        value[j] = ck;
        value[k] = cj;
        if (Character.isSurrogate(cj) ||
            Character.isSurrogate(ck)) {
            hasSurrogates = true;
        }
    }
    if (hasSurrogates) {
        reverseAllValidSurrogatePairs();
    }
    return this;
}

private void reverseAllValidSurrogatePairs() {
    for (int i = 0; i < count - 1; i++) {
        char c2 = value[i];
        if (Character.isLowSurrogate(c2)) {
            char c1 = value[i + 1];
            if (Character.isHighSurrogate(c1)) {
                value[i++] = c1;
                value[i] = c2;
            }
        }
    }
}

最后,该类提供了一个抽象的toString方法,该方法继承自CharSequence接口。

@Override
public abstract String toString();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值