AbstractStringBuilder源码分析

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

1
2
3
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。

1
2
char[] value;
int count;

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

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public int length() {
return count;
}

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

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

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

1
2
3
4
5
6
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值范围或者超出数组最大容量,就在指定容量和数组最大容量中选择最大的作为新数组的容量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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()方法是将字符串的容量降为已被使用的容量大小。

1
2
3
4
5
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}

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

1
2
3
4
5
6
7
8
9
10
11
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的方法。

1
2
3
4
5
6
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)中。

1
2
3
4
5
6
7
8
9
10
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的字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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指定位置之后的字符向后移动给被插入的字符串空出位置,最后插入字符串。

1
2
3
4
5
6
7
8
9
10
11
12
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方法可以删除字符串的子串。

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

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

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

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

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

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

1
2
3
4
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方法将字符串反转,以后可以借鉴该方法的实现,从中间开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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接口。

1
2
@Override
public abstract String toString();
-------------本文结束感谢您的阅读-------------

本文标题:AbstractStringBuilder源码分析

文章作者:huihui

发布时间:2018年11月20日 - 00:11

最后更新:2019年02月14日 - 19:02

原始链接:http://101.200.47.120:8011/2018/11/20/AbstractStringBuilder源码分析/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。