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