大多数状况下, StringBuffer 的速度要比 String 快; StringBuilder 要比StringBuffer快;StringBuffer 和 StringBuilder 都是 AbstractStringBuilder 的子类,区别在于StringBuffer 的方法大部分都有 synchronized 修饰。java
/** * 用来存储字符的数组 * 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]; }
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)); } } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 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; }
扩容的方法最终由 newCapacity()
实现的,首先将容量左移一位(即扩大2倍)同时加2,若是此时任小于指定的容量,那么就将容量设置为 minimumCapacity
。而后判断是否溢出,经过 hugeCapacity
实现,若是溢出了(长度大于 Integer.MAX_VALUE
),则抛错( OutOfMemoryError
);不然根据 minCapacity
和 Integer.MAX_VALUE - 8
的大小比较肯定数组容量为 max(minCapacity, Integer.MAX_VALUE - 8)
。最后将 value
值进行拷贝,这一步显然是最耗时的操做。c++
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; }
append()
是最经常使用的方法,它有不少形式的重载。上面是最经常使用的一种,用于追加字符串。若是 str
是 null
,则直接调用
appendNull()
方法。这个方法就是直接追加 'n'
、 'u'
、'l'
、'l'
这几个字符,方法以下:git
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; }
若是不是null
,则首先须要判断数组容量是否足够,不够则须要扩容(扩容则是调用上述分析的扩容方法);
而后调用 String
的 getChars()
方法将 str
追加到 value
末尾;
最后返回对象自己,因此 append()
能够连续调用(就是一种相似于链式编程)。github
Java
开发者认为咱们在 append
数据的时候,中间常常会加一个分隔符,刚好这个分隔符在 Java
中正好占用两个字节。也不知道分析的对不对,有其余意见的大佬们能够在 issue经过查看源码分析发现二者都继承至 AbstractStringBuilder
。 而 StringBuffer
之因此是线程安全的,是由于重写 AbstractStringBuilder
的方法的时候在前面加上了 synchronzied
修饰这些方法;而 StringBuilder
重写的时候只是直接调用父类的方法,没有作其余的操做。编程
其实经过阅读源码发现 StringBuilder
和 StringBuffer
之间的关系,相似于 HashMap
和 HashTable
之间的关系。数组