stringBuilder 源码学习
jdk: 1.8
类定义
/**
* A mutable sequence of characters. This class provides an API compatible
* with {@code StringBuffer}, but with no guarantee of synchronization.
* This class is designed for use as a drop-in replacement for
* {@code StringBuffer} in places where the string buffer was being
* used by a single thread (as is generally the case). Where possible,
* it is recommended that this class be used in preference to
* {@code StringBuffer} as it will be faster under most implementations.
*
* <p>The principal operations on a {@code StringBuilder} are the
* {@code append} and {@code insert} methods, which are
* overloaded so as to accept data of any type. Each effectively
* converts a given datum to a string and then appends or inserts the
* characters of that string to the string builder. The
* {@code append} method always adds these characters at the end
* of the builder; the {@code insert} method adds the characters at
* a specified point.
* <p>
* For example, if {@code z} refers to a string builder object
* whose current contents are "{@code start}", then
* the method call {@code z.append("le")} would cause the string
* builder to contain "{@code startle}", whereas
* {@code z.insert(4, "le")} would alter the string builder to
* contain "{@code starlet}".
* <p>
* In general, if sb refers to an instance of a {@code StringBuilder},
* then {@code sb.append(x)} has the same effect as
* {@code sb.insert(sb.length(), x)}.
* <p>
* Every string builder has a capacity. As long as the length of the
* character sequence contained in the string builder does not exceed
* the capacity, it is not necessary to allocate a new internal
* buffer. If the internal buffer overflows, it is automatically made larger.
*
* <p>Instances of {@code StringBuilder} are not safe for
* use by multiple threads. If such synchronization is required then it is
* recommended that {@link java.lang.StringBuffer} be used.
*
* <p>Unless otherwise noted, passing a {@code null} argument to a constructor
* or method in this class will cause a {@link NullPointerException} to be
* thrown.
*
* @author Michael McCloskey
* @see java.lang.StringBuffer
* @see java.lang.String
* @since 1.5
*/
public final class StringBuilder
extends AbstractStringBuilder
implements Serializable, CharSequence
{
/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;
接口
实现了 Serializable 和 CharSequence 接口。
CharSequence 接口
public interface CharSequence {
/**
* 长度
*/
int length();
/**
* 指定位置
*/
char charAt(int index);
/**
* 截取
*/
CharSequence subSequence(int start, int end);
/**
* Returns a string containing the characters in this sequence in the same
* order as this sequence. The length of the string will be the length of
* this sequence.
*
* @return a string consisting of exactly this sequence of characters
*/
public String toString();
/**
* Returns a stream of {@code int} zero-extending the {@code char} values
* from this sequence. Any char which maps to a <a
* href="{@docRoot}/java/lang/Character.html#unicode">surrogate code
* point</a> is passed through uninterpreted.
*
* <p>If the sequence is mutated while the stream is being read, the
* result is undefined.
*
* @return an IntStream of char values from this sequence
* @since 1.8
*/
public default IntStream chars() {
// 迭代器
class CharIterator implements PrimitiveIterator.OfInt {
int cur = 0;
public boolean hasNext() {
return cur < length();
}
public int nextInt() {
if (hasNext()) {
return charAt(cur++);
} else {
throw new NoSuchElementException();
}
}
@Override
public void forEachRemaining(IntConsumer block) {
for (; cur < length(); cur++) {
block.accept(charAt(cur));
}
}
}
return StreamSupport.intStream(() ->
Spliterators.spliterator(
new CharIterator(),
length(),
Spliterator.ORDERED),
Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED,
false);
}
/**
* Returns a stream of code point values from this sequence. Any surrogate
* pairs encountered in the sequence are combined as if by {@linkplain
* Character#toCodePoint Character.toCodePoint} and the result is passed
* to the stream. Any other code units, including ordinary BMP characters,
* unpaired surrogates, and undefined code units, are zero-extended to
* {@code int} values which are then passed to the stream.
*
* <p>If the sequence is mutated while the stream is being read, the result
* is undefined.
*
* @return an IntStream of Unicode code points from this sequence
* @since 1.8
*/
public default IntStream codePoints() {
class CodePointIterator implements PrimitiveIterator.OfInt {
int cur = 0;
@Override
public void forEachRemaining(IntConsumer block) {
final int length = length();
int i = cur;
try {
while (i < length) {
char c1 = charAt(i++);
if (!Character.isHighSurrogate(c1) || i >= length) {
block.accept(c1);
} else {
char c2 = charAt(i);
if (Character.isLowSurrogate(c2)) {
i++;
block.accept(Character.toCodePoint(c1, c2));
} else {
block.accept(c1);
}
}
}
} finally {
cur = i;
}
}
public boolean hasNext() {
return cur < length();
}
public int nextInt() {
final int length = length();
if (cur >= length) {
throw new NoSuchElementException();
}
char c1 = charAt(cur++);
if (Character.isHighSurrogate(c1) && cur < length) {
char c2 = charAt(cur);
if (Character.isLowSurrogate(c2)) {
cur++;
return Character.toCodePoint(c1, c2);
}
}
return c1;
}
}
return StreamSupport.intStream(() ->
Spliterators.spliteratorUnknownSize(
new CodePointIterator(),
Spliterator.ORDERED),
Spliterator.ORDERED,
false);
}
}
构造器
public StringBuilder() {
super(16);
}
/**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
public StringBuilder(int capacity) {
super(capacity);
}
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string builder that contains the same characters
* as the specified {@code CharSequence}. The initial capacity of
* the string builder is {@code 16} plus the length of the
* {@code CharSequence} argument.
*
* @param seq the sequence to copy.
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
char[]
这里直接继承了父类的构造器:
AbstractStringBuilder() {
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
创建一个指定大小的 char 数组
各种 append 方法
append(string)
还有就是初始化对应的 seq 序列,通过 append 方法:
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
引用父类:
public AbstractStringBuilder append(String str) {
if (str == null)
// null 直接添加 'null'
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
可能需要扩容:
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
// 通过数组 copy 的方式
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
新容量的计算:
private int newCapacity(int minCapacity) {
// overflow-conscious code
// 翻倍+2
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
其中的 getChars 实现如下:
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
// 系统的数组拷贝,性能比较好。
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
append(chars[], start, end)
@Override
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
底层实现依然是通过系统的数组拷贝:
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
}
当然依然涉及到一次可能的扩容。
toString()
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
这里创建了一个 copy,新的 String。