一般情况下问道这个问题,最普通的回答是String是不可变对象,StringBuilder是可变的,而StringBuffer是同步的。
那到底为什么是这样呢?
首先看String源码的定义:
String中value和coder都声明成final ,所以当然是不可变的。
@Stable
private final byte[] value;
/**
* The identifier of the encoding used to encode the bytes in
* {@code value}. The supported values in this implementation are
*
* LATIN1
* UTF16
*
* @implNote This field is trusted by the VM, and is a subject to
* constant folding if String instance is constant. Overwriting this
* field after construction will cause problems.
*/
private final byte coder;
/** Cache the hash code for the string */
private int hash; // Default to 0
public String() {
this.value = "".value;
this.coder = "".coder;
}
然后StringBuilder:继承了AbstractStringBuilder:
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
}
那么再看看AbstractStringBuilder构造方法的实现:都不是final的,那么StringBuilder底层实现是数组实现的,再增加元素的时候一定会产生数组长度不够的问题,如果大家有耐心继续往下追踪源码,会发现使用Arrays.copyOf实现的append方法时候的长度不足,Arrays.copyOf里又是通过System.arraycopy实现的,而这个System.arraycopy是一个native方法,也就是说这个方法的实现不是Java语言,如果一直追踪下去,这个方法看起来像一个接口,因为只有声明没有实现,但是这个方法实际上是已经被实现了,只是不是用Java语言实现,因此这个方法前面的修饰符和Java中其他方法修饰符一样,唯独不能使用abstract,因为abstract声明的是没有被实现的方法,而native方法已经被实现了。
System.arraycopy
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
byte[] value;
/**
* The id of the encoding used to encode the bytes in {@code value}.
*/
byte coder;
/**
* The count is the number of characters used.
*/
int count;
private static final byte[] EMPTYVALUE = new byte[0];
/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
value = EMPTYVALUE;
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
if (COMPACT_STRINGS) {
value = new byte[capacity];
coder = LATIN1;
} else {
value = StringUTF16.newBytesFor(capacity);
coder = UTF16;
}
}
}
最后StringBuffer是如何实现同步的?一般实现同步都是加上synchronized关键字,StringBuffer也一样,给方法前面加上synchronized,在方法执行的时候获得一把锁,只有当自己执行完了才释放锁,因此也就实现了同步,各个方法之间互不影响。