抽象类AbstractStringBuilder
实现了接口Appendable
和CharSequence
,接口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();