我们知道,在java中,如果要对于一个字符串进行操作,比如增删操作,如果直接用+
来进行的话,效率是比较低的。作为替代,我们一般使用StringBuilder
来进行这样的操作。
所以,这一次,我们就来研究一下StringBuilder的源码
构造函数
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence{ /** use serialVersionUID for interoperability */ static final long serialVersionUID = 4383685877147921099L; /** * Constructs a string builder with no characters in it and an * initial capacity of 16 characters. */ 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); } ...}
可以看到,当我们不指定初始的容量的时候,会调用父类AbstractStringBuilder
的构造函数,并默认初始容量为16。
所以,我们来看看’AbstractStringBuilder’的构造方法:
abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * The value is used for character storage. */ char[] value; /** * The count is the number of characters used. */ int count; /** * This no-arg constructor is necessary for serialization of subclasses. */ AbstractStringBuilder() { } /** * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { value = new char[capacity]; } ...}
其中,主要关注:
AbstractStringBuilder(int capacity) { value = new char[capacity]; }
可以看到,在这里根据设定的初始容量,初始化出了一个相应长度的char型数组value
。
append方法
这里以str的append
方法为例,看一下StringBuilder的append方法是怎样工作的。
首先是StringBuilder
中的append(String str)
方法。
public StringBuilder append(String str) { super.append(str); return this;}
指向了父类中的append
方法,那么就来看看父类中的定义:
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;}
其中的ensureCapacityInternal
是为了保证容量能够装得下这个输入的str。
private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); }}private int newCapacity(int minCapacity) { // overflow-conscious code 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) { // overflow throw new OutOfMemoryError(); } return (minCapacity > MAX_ARRAY_SIZE) ? minCapacity : MAX_ARRAY_SIZE;}
这里的扩容方式为先将容量乘2再加2,再与所需容量进行比较,若小于所需容量,则取所需容量,后面还有防止溢出的操作,写得非常严谨,这里值得我们学习与借鉴。获得更新后的容量后,新建一个新的容量的数组,并将之前的数据用Arrays.copyOf()
方法复制进去,并更新为新的成员变量value
。
我们回到append
方法中来,在进行完ensureCapacityInternal
后,就要将所需添加的数据加进来了,这里调用的是String
的getChars
方法。
# String.javapublic 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);}
这里调用System.arraycopy
来将String
内部的成员变量char型数组value
(注意这里是String的,也就是append的参数里的那个变量)从0到str.length(),也就是所有成员,复制到dst中,也就是StringBuilder
的成员变量value
中。之后,便完成了整个append
的操作。