# 前言

StringBuilderStringBuilder都是字符串操作类。它们都继承了AbstractStringBuilder抽象类,并且都实现了CharSequenceSerializable接口。它们和String的区别在于它们的value数组没有被final修饰符修饰,所以是可变的。它们之间的区别是StringBuffer的方法是由synchronized关键字修饰,所以是线程安全的。
image.png

# AbstractStringBuilder

AbstractStringBuilderStringBuilderStringBuffer共同继承的抽象类,它为子类提供了大部分的实现。

| 成员变量 & 构造方法

  1. // 维护一个字符数组
  2. char[] value;
  3. // 字符的个数
  4. int count;
  5. // 构造方法
  6. AbstractStringBuilder() {
  7. }
  8. // 指定初始化容量
  9. AbstractStringBuilder(int capacity) {
  10. value = new char[capacity];
  11. }

| 扩容

  1. // minimumCapacity: 需要的最小容量
  2. public void ensureCapacity(int minimumCapacity) {
  3. if (minimumCapacity > 0)
  4. ensureCapacityInternal(minimumCapacity);
  5. }
  6. private void ensureCapacityInternal(int minimumCapacity) {
  7. // 如果所需要的容量大于当前容量,则进行扩容,使用Arrays.copyOf()
  8. if (minimumCapacity - value.length > 0) {
  9. value = Arrays.copyOf(value,
  10. newCapacity(minimumCapacity));
  11. }
  12. }
  13. // 数组长度的最大值
  14. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  15. private int newCapacity(int minCapacity) {
  16. // 新容量 = 2 * 旧容量 + 2
  17. int newCapacity = (value.length << 1) + 2;
  18. // 如果新容量仍不够大,将新容量设置为所需要容量
  19. if (newCapacity - minCapacity < 0) {
  20. newCapacity = minCapacity;
  21. }
  22. // 如果新容量 > MAX_ARRAY_SIZE or < 0
  23. return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
  24. // 进一步判断
  25. ? hugeCapacity(minCapacity)
  26. // 否则,直接返回新容量
  27. : newCapacity;
  28. }
  29. private int hugeCapacity(int minCapacity) {
  30. // 如果需要的容量大于整型最大值,抛出 OutOfMemoryError
  31. if (Integer.MAX_VALUE - minCapacity < 0) {
  32. throw new OutOfMemoryError();
  33. }
  34. // 所需容量 > MAX_ARRAY_SIZE,返回所需要容量
  35. // 所需容量 < MAX_ARRAY_SIZE,返回 MAX_ARRAY_SIZE
  36. return (minCapacity > MAX_ARRAY_SIZE)
  37. ? minCapacity : MAX_ARRAY_SIZE;
  38. }

在一些虚拟机中会为数组保留一些 header words,所以为了防止OutOfMemoryErrorMAX_ARRAY_SIZE设置为整型的最大值减 8。总的来说,扩容机制的过程如下:

  1. 新容量 = 旧容量 * 2 + 2,如果新容量仍然不能满足,数组长度直接设置为所需容量。
  2. 如果新容量小于MAX_ARRAY_SIZE,直接返回新容量。
  3. 否则,当所需容量大于整型最大值时抛出异常。
  4. 如果所需容量 > MAX_ARRAY_SIZE,直接返回所需容量,否则返回MAX_ARRAY_SIZE

    | append()

    append()是整个类的核心方法,拥有多个重载方法,这里主要分析以String为参数的方法。 ```java public AbstractStringBuilder append(String str) { if (str == null)
    1. return appendNull();
    int len = str.length(); // 扩容 ensureCapacityInternal(count + len); // 调用String.getChars()将str添加到value末尾,本质是调用System.arraycopy() str.getChars(0, len, value, count); // 更新字符长度 count += len; // 返回自身,实现链式调用 return this; }

private AbstractStringBuilder appendNull() { int c = count; ensureCapacityInternal(c + 4); final char[] value = this.value; // 添加’n’, ‘u’, ‘l’, ‘l’四个字符到value数组中 value[c++] = ‘n’; value[c++] = ‘u’; value[c++] = ‘l’; value[c++] = ‘l’; count = c; return this; }

  1. <a name="YaRLd"></a>
  2. # # StringBuilder
  3. <a name="BwFXm"></a>
  4. ## | 构造函数
  5. ```java
  6. // 默认初始化容量16
  7. public StringBuilder() {
  8. super(16);
  9. }
  10. // 指定初始化容量
  11. public StringBuilder(int capacity) {
  12. super(capacity);
  13. }
  14. // 直接传入一个String
  15. public StringBuilder(String str) {
  16. super(str.length() + 16);
  17. append(str);
  18. }
  19. // 传入一个字符序列
  20. public StringBuilder(CharSequence seq) {
  21. this(seq.length() + 16);
  22. append(seq);
  23. }

| append()

  1. @Override
  2. public StringBuilder append(String str) {
  3. super.append(str);
  4. return this;
  5. }

# StringBuffer

方法实现基本和StringBuilder相同,但是被synchronized关键字修饰,保证了方法的线程安全。
append()为例:

  1. // 实现和StringBuilder相同,但是添加的synchronized关键字保证了线程安全
  2. @Override
  3. public synchronized StringBuffer append(String str) {
  4. toStringCache = null;
  5. super.append(str);
  6. return this;
  7. }

| toStringCache & toString()

StringBuffer的任何写方法都会对toStringCache重设为null,该变量保存了最近一次toString()方法的缓存。

  1. // 最近一次toString()的缓存,任何写操作都会将该变量重设为null
  2. private transient char[] toStringCache;
  3. @Override
  4. public synchronized String toString() {
  5. // 如果缓存为空,则填充缓存
  6. if (toStringCache == null) {
  7. toStringCache = Arrays.copyOfRange(value, 0, count);
  8. }
  9. // 返回使用缓存new的String对象
  10. return new String(toStringCache, true);
  11. }
  12. // 该方法不是直接复制,而是将String中的value指向toStringCache
  13. String(char[] value, boolean share) {
  14. // assert share : "unshared not supported";
  15. this.value = value;
  16. }

# 总结

  1. 可变性:
    • String是不可变的;
    • StringBuilderStringBuilder没有使用finalprivate关键字修饰底层的value数组。
  2. 线程安全性:
    • String对象是不可变的,线程安全;
    • StringBuffer的写方法具有同步锁,线程安全;
    • StringBuilder的写法发没有同步锁,线程不安全;
  3. 性能:
    • String类型改变时会生成一个新的String对象,并用指针指向它。
    • StringBuffer每次对本身进行操作。
    • 相同情况使用StringBuilder性能提高 10% ~ 15%,但是存在多线程不安全的风险。
  4. 使用:
    • String适合操作少量数据。
    • StringBuilder适合单线程操作字符串缓冲区下操作大量数据。
    • StringBuffer适合多线程操作字符串缓冲区下操作大量数据。