在学java的过程中,大家往往会被告知连接字符串建议用StringBuilder而不是用+来连接,这是为什么呢?今天我们就来从源码角度分析来解决这个问题。
以下是jdk1.8中StringBuilder的代码
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
//......
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
[@Override](https://my.oschina.net/u/1162528)
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
[@Override](https://my.oschina.net/u/1162528)
public StringBuilder append(String str) {
super.append(str);
return this;
}
[@Override](https://my.oschina.net/u/1162528)
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
//.......
}
由以上代码可以看出StringBuilder绝大多数方法直接调用的父类的方法然后返回对象本身
接下来来看看父类AbstractStringBuilder的源代码:
public abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
public int length(){return count;}
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
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;
}
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);
}
[@Override](https://my.oschina.net/u/1162528)
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;
}
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(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
}
可以看到AbstractStringBuilder在连接字符串时只是对字符数组扩容(本质上是构造一个更长的字符数组),然后将要连接的两个字符串拷贝进数组,而用+连接String 则会直接构造一个新的String对象来存放连接后的字符串(显然String对象比字符数组更占空间,因为String对象包含一个同等长度的字符数组,并且还包含其他属性和方法),所以在连接字符串时建议使用StringBuilder而不是用+来连接字符串。