Java源码系列(4) -- AbstractStringBuilder

March 25, 2017

一、类签名

AbstractStringBuilderStringBuilderStringBuffer的父类,包含字符串操作的实现逻辑,子类根据各自需求对方法调用做同步处理,类本身线程不安全。作为可变字符串的父类,借助字符数组的形式实现可变字符串,类中大部分方法是字符修改、插入、追加等操作。

1
abstract class AbstractStringBuilder implements Appendable, CharSequence

二、数据成员

保存字符串的数组

1
char[] value;

记录字符长度

1
int count;

三、构造方法

必要的无参构造方法,用于序列化

1
AbstractStringBuilder() { }

通过指定容量构造字符串数组

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

四、成员方法

4.1 长度相关

已保存在字符串数组的字符个数

1
2
3
4
@Override
public int length() {
    return count;
}

字符串数组的空间长度,包含可插入新字符的空间,总有length() <= capacity()

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

4.2 增加容量

保证字符数组大小至少要和具体的最小值相等。若当前容量小于参数具体值,则创建一个更大的数组,数值取下列之大者:

  • minimumCapacity大小;
  • 原容量值的两倍

若minimumCapacity不可用,下列直接退出。本类有方法减少字符数组的长度

1
2
3
4
public void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > 0)
        ensureCapacityInternal(minimumCapacity);
}

包含参数检查,最小容量不得小于已有字符串数组长度,没有同步特性

1
2
3
4
5
private void ensureCapacityInternal(int minimumCapacity) {
    // 仅minimumCapacity大于数组长度可用
    if (minimumCapacity - value.length > 0)
        expandCapacity(minimumCapacity);
}

容量扩增方法,没有大小检查或加入同步特性

1
2
3
4
5
6
7
8
9
10
11
void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - minimumCapacity < 0)
        newCapacity = minimumCapacity;
    if (newCapacity < 0) {
        if (minimumCapacity < 0) // 下溢
            throw new OutOfMemoryError();
        newCapacity = Integer.MAX_VALUE;
    }
    value = Arrays.copyOf(value, newCapacity);
}

4.3 裁剪、增加

可变字符数组有空余用于插入更多字符,可以通过裁剪达到提高内存利用率的目的。 如果内存空间不紧张或没有特殊要求,不要使用这个方法,因为向裁剪后的字符数组添加字符一定会引起扩容。而且裁剪也是一次数据内容拷贝的过程,超大数组的情况下可能会引起性能问题。

实现方式:把字符串拷贝到长度刚好合适的字符数组中返回,释放原数组空间

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

通过添加字符’\0’,令字符串长度达到newLength,仅在newLength大于数组内字符串长度有效。

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

4.4 查找

返回指定索引值下的字符

1
2
3
4
5
6
@Override
public char charAt(int index) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    return value[index];
}

返回指定索引下字符的编码值

1
2
3
4
5
6
public int codePointAt(int index) {
    if ((index < 0) || (index >= count)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return Character.codePointAtImpl(value, index, count);
}

返回指定索引前一位字符的编码值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public int codePointBefore(int index) {
    int i = index - 1;
    if ((i < 0) || (i >= count)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return Character.codePointBeforeImpl(value, index, 0);
}

public int codePointCount(int beginIndex, int endIndex) {
    if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
        throw new IndexOutOfBoundsException();
    }
    return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
}

public int offsetByCodePoints(int index, int codePointOffset) {
    if (index < 0 || index > count) {
        throw new IndexOutOfBoundsException();
    }
    return Character.offsetByCodePointsImpl(value, 0, count,
                                            index, codePointOffset);
}

复制指定范围的字符串到给定的字符数组中

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);
}

4.5 append

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
public AbstractStringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

// 因为同步特性的差异,具体请看子类的文档说明(注:StringBuilder和StringBuffer)
public AbstractStringBuilder append(StringBuffer sb) {
    if (sb == null)
        return appendNull();
    int len = sb.length();
    ensureCapacityInternal(count + len);
    sb.getChars(0, len, value, count);
    count += len;
    return this;
}

AbstractStringBuilder append(AbstractStringBuilder asb) {
    if (asb == null)
        return appendNull();
    int len = asb.length();
    ensureCapacityInternal(count + len);
    asb.getChars(0, len, value, count);
    count += len;
    return this;
}

// 因为同步特性的差异,具体请看子类的文档说明(注:StringBuilder和StringBuffer)
@Override
public AbstractStringBuilder append(CharSequence s) {
    if (s == null)
        return appendNull();
    if (s instanceof String)
        return this.append((String)s);
    if (s instanceof AbstractStringBuilder)
        return this.append((AbstractStringBuilder)s);

    return this.append(s, 0, s.length());
}

private AbstractStringBuilder appendNull() {
    int c = count;
    ensureCapacityInternal(c + 4);
    final char[] value = this.value;
    value[c++] = 'n';
    value[c++] = 'u';
    value[c++] = 'l';
    value[c++] = 'l';
    count = c;
    return this;
}

@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
    if (s == null)
        s = "null";
    if ((start < 0) || (start > end) || (end > s.length()))
        throw new IndexOutOfBoundsException(
            "start " + start + ", end " + end + ", s.length() "
            + s.length());
    int len = end - start;
    ensureCapacityInternal(count + len);
    for (int i = start, j = count; i < end; i++, j++)
        value[j] = s.charAt(i);
    count += len;
    return this;
}

public AbstractStringBuilder append(char[] str) {
    int len = str.length;
    ensureCapacityInternal(count + len);
    System.arraycopy(str, 0, value, count, len);
    count += len;
    return this;
}

public AbstractStringBuilder append(char str[], int offset, int len) {
    if (len > 0)
        ensureCapacityInternal(count + len);
    System.arraycopy(str, offset, value, count, len);
    count += len;
    return this;
}

public AbstractStringBuilder append(boolean b) {
    if (b) {
        ensureCapacityInternal(count + 4);
        value[count++] = 't';
        value[count++] = 'r';
        value[count++] = 'u';
        value[count++] = 'e';
    } else {
        ensureCapacityInternal(count + 5);
        value[count++] = 'f';
        value[count++] = 'a';
        value[count++] = 'l';
        value[count++] = 's';
        value[count++] = 'e';
    }
    return this;
}

@Override
public AbstractStringBuilder append(char c) {
    ensureCapacityInternal(count + 1);
    value[count++] = c;
    return this;
}

public AbstractStringBuilder append(int i) {
    if (i == Integer.MIN_VALUE) {
        append("-2147483648");
        return this;
    }
    int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
                                 : Integer.stringSize(i);
    int spaceNeeded = count + appendedLength;
    ensureCapacityInternal(spaceNeeded);
    Integer.getChars(i, spaceNeeded, value);
    count = spaceNeeded;
    return this;
}

public AbstractStringBuilder append(long l) {
    if (l == Long.MIN_VALUE) {
        append("-9223372036854775808");
        return this;
    }
    int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
                                 : Long.stringSize(l);
    int spaceNeeded = count + appendedLength;
    ensureCapacityInternal(spaceNeeded);
    Long.getChars(l, spaceNeeded, value);
    count = spaceNeeded;
    return this;
}

public AbstractStringBuilder append(float f) {
    FloatingDecimal.appendTo(f,this);
    return this;
}

public AbstractStringBuilder append(double d) {
    FloatingDecimal.appendTo(d,this);
    return this;
}

public AbstractStringBuilder appendCodePoint(int codePoint) {
    final int count = this.count;

    if (Character.isBmpCodePoint(codePoint)) {
        ensureCapacityInternal(count + 1);
        value[count] = (char) codePoint;
        this.count = count + 1;
    } else if (Character.isValidCodePoint(codePoint)) {
        ensureCapacityInternal(count + 2);
        Character.toSurrogates(codePoint, value, count);
        this.count = count + 2;
    } else {
        throw new IllegalArgumentException();
    }
    return this;
}

4.6 移除字符

移除字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public AbstractStringBuilder delete(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        end = count;
    if (start > end)
        throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) {
        System.arraycopy(value, start+len, value, start, count-end);
        count -= len;
    }
    return this;
}

移除一个字符

1
2
3
4
5
6
7
public AbstractStringBuilder deleteCharAt(int index) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    System.arraycopy(value, index+1, value, index, count-index-1);
    count--;
    return this;
}

4.7 替换

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
public AbstractStringBuilder replace(int start, int end, String str) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (start > count)
        throw new StringIndexOutOfBoundsException("start > length()");
    if (start > end)
        throw new StringIndexOutOfBoundsException("start > end");

    if (end > count)
        end = count;
    int len = str.length();
    int newCount = count + len - (end - start);
    ensureCapacityInternal(newCount);

    System.arraycopy(value, end, value, start + len, count - end);
    str.getChars(value, start);
    count = newCount;
    return this;
}

public void setCharAt(int index, char ch) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    value[index] = ch;
}

4.8 获取子序列

从指定起点获取后面字符序列,结果是String

1
2
3
public String substring(int start) {
    return substring(start, count);
}

获取给定范围内的字符序列,结果是CharSequence

1
2
3
4
@Override
public CharSequence subSequence(int start, int end) {
    return substring(start, end);
}

获取给定范围内的字符序列,结果是String

1
2
3
4
5
6
7
8
9
public String substring(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        throw new StringIndexOutOfBoundsException(end);
    if (start > end)
        throw new StringIndexOutOfBoundsException(end - start);
    return new String(value, start, end - start);
}

4.9 insert

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public AbstractStringBuilder insert(int index, char[] str, int offset,
                                    int len)
{
    if ((index < 0) || (index > length()))
        throw new StringIndexOutOfBoundsException(index);
    if ((offset < 0) || (len < 0) || (offset > str.length - len))
        throw new StringIndexOutOfBoundsException(
            "offset " + offset + ", len " + len + ", str.length "
            + str.length);
    ensureCapacityInternal(count + len);
    System.arraycopy(value, index, value, index + len, count - index);
    System.arraycopy(str, offset, value, index, len);
    count += len;
    return this;
}

public AbstractStringBuilder insert(int offset, Object obj) {
    return insert(offset, String.valueOf(obj));
}

public AbstractStringBuilder insert(int offset, String str) {
    if ((offset < 0) || (offset > length()))
        throw new StringIndexOutOfBoundsException(offset);
    if (str == null)
        str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    System.arraycopy(value, offset, value, offset + len, count - offset);
    str.getChars(value, offset);
    count += len;
    return this;
}

public AbstractStringBuilder insert(int offset, char[] str) {
    if ((offset < 0) || (offset > length()))
        throw new StringIndexOutOfBoundsException(offset);
    int len = str.length;
    ensureCapacityInternal(count + len);
    System.arraycopy(value, offset, value, offset + len, count - offset);
    System.arraycopy(str, 0, value, offset, len);
    count += len;
    return this;
}

public AbstractStringBuilder insert(int dstOffset, CharSequence s) {
    if (s == null)
        s = "null";
    if (s instanceof String)
        return this.insert(dstOffset, (String)s);
    return this.insert(dstOffset, s, 0, s.length());
}

 public AbstractStringBuilder insert(int dstOffset, CharSequence s,
                                     int start, int end) {
    if (s == null)
        s = "null";
    if ((dstOffset < 0) || (dstOffset > this.length()))
        throw new IndexOutOfBoundsException("dstOffset "+dstOffset);
    if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
        throw new IndexOutOfBoundsException(
            "start " + start + ", end " + end + ", s.length() "
            + s.length());
    int len = end - start;
    ensureCapacityInternal(count + len);
    System.arraycopy(value, dstOffset, value, dstOffset + len,
                     count - dstOffset);
    for (int i=start; i<end; i++)
        value[dstOffset++] = s.charAt(i);
    count += len;
    return this;
}

public AbstractStringBuilder insert(int offset, boolean b) {
    return insert(offset, String.valueOf(b));
}

public AbstractStringBuilder insert(int offset, char c) {
    ensureCapacityInternal(count + 1);
    System.arraycopy(value, offset, value, offset + 1, count - offset);
    value[offset] = c;
    count += 1;
    return this;
}

public AbstractStringBuilder insert(int offset, int i) {
    return insert(offset, String.valueOf(i));
}

public AbstractStringBuilder insert(int offset, long l) {
    return insert(offset, String.valueOf(l));
}

public AbstractStringBuilder insert(int offset, float f) {
    return insert(offset, String.valueOf(f));
}

public AbstractStringBuilder insert(int offset, double d) {
    return insert(offset, String.valueOf(d));
}

4.10 查索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public int indexOf(String str) {
    return indexOf(str, 0);
}

public int indexOf(String str, int fromIndex) {
    return String.indexOf(value, 0, count, str, fromIndex);
}

public int lastIndexOf(String str) {
    return lastIndexOf(str, count);
}

public int lastIndexOf(String str, int fromIndex) {
    return String.lastIndexOf(value, 0, count, str, fromIndex);
}

4.11 字符序列翻转

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;
            }
        }
    }
}

4.12 其他

获取字符串序列

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