抽象类 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(); |