【问题标题】:How is capacity increased in StringBuffer?StringBuffer 的容量是如何增加的?
【发布时间】:2018-02-06 07:25:02
【问题描述】:

我们知道 StringBuffer 的默认容量是 16,当我们尝试添加第 17 个字符时,它将按照以下规则增加:

newCapacity =(当前容量+1)*2;

StringBuffer sb = new StringBuffer();
sb.append("aaaaaaaaaaaaaaaa"); // length is 16
System.out.println(sb.capacity()); // it gives 16

如果我添加第 17 个字符

StringBuffer sb = new StringBuffer();
sb.append("aaaaaaaaaaaaaaaaa"); // length is 17
System.out.println(sb.capacity()); // it gives 34

但现在令人困惑的部分

如果我尝试添加 35 个字符

StringBuffer sb = new StringBuffer();
sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // length is 35
System.out.println(sb.capacity()); // it gives 35 

此时容量应该增加了 70。

有趣的部分是

StringBuffer sb = new StringBuffer();
sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // length is 34
sb.append("a"); // added 35th char
System.out.println(sb.capacity()); // it gives 70  which is correct

任何人都可以对此有所了解吗?

【问题讨论】:

  • this 可能会有所启发!
  • 你的StringBuilder和StringBuffer不一致。请选择一个并坚持下去,或者说清楚为什么要在两者之间进行转换。
  • 它只是StringBuffer,这是我的标题错误

标签: stringbuffer


【解决方案1】:

StringBuffer 中的 expandCapacity 会:

int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
    newCapacity = minimumCapacity;

由于 value.length 在您的 35 示例中当时是 16,因此它将使用 35(在 minimumCapacity 中给出)。然而,在最后一个示例中,在最后一个 append 期间,value.length 为 34,minimumCapacity 为 35,因此新容量将为 value.length * 2 + 2

【讨论】:

  • 那么如果我添加第 17 个字符 StringBuffer sb = new StringBuffer(); sb.append("aaaaaaaaaaaaaaaa"); // 长度为 17 System.out.println(sb.capacity()); // 它给出 34(根据你的逻辑它应该给出 17)
  • 你是对的 - value.length 是实际容量,而不是实际长度,因此在第一个示例(初始容量)中它将是 16,并且在示例中也会形成您的评论。然后在您的评论中 16*2+2 将高于 17 因此将被使用。
【解决方案2】:

具体细节可能稍有取决于 JDK 版本,但取决于我的本地版本 1.8.0_66:

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;
}

private void ensureCapacityInternal(int minimumCapacity) {
    if (minimumCapacity - value.length > 0)
        expandCapacity(minimumCapacity);
}

void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - minimumCapacity < 0)
        newCapacity = minimumCapacity;
    if (newCapacity < 0) {
        if (minimumCapacity < 0) // overflow
            throw new OutOfMemoryError();
        newCapacity = Integer.MAX_VALUE;
    }
    value = Arrays.copyOf(value, newCapacity);
}

请注意,value.length 实际上是容量,而不是正在存储的字符串的长度。当前缓冲区中的字符数为count!还记得在调用new StringBuffer() 时,value.length 最初是 16。考虑到这些,让我们对您介绍的每个案例进行一点堆栈跟踪。

对于大小为 17 的字符串:

sb.append("12345678901234567")  
    if (str == null) -> false
    len = 17;
    ensureCapacityInternal(0 + 17)
        if (17 - 16 > 0) -> true
            expandCapacity(17)
                newCapacity = 16 * 2 + 2 = 34
                if (34 - 17 < 0) -> false
                value = Arrays.copyOf("", 34)
    str.getChars(0, 17, "", 17)
    return this
sb.build() -> "12345678901234567"
sb.capacity() -> 34

对于大小为 35 的字符串:

sb.append("12345678901234567890123456789012345") 
    if (str == null) -> false
    len = 35;
    ensureCapacityInternal(0 + 35)
        if (35 - 16 > 0) -> true
            expandCapacity(35)
                newCapacity = 16 * 2 + 2 = 34
                if (34 - 35 < 0) -> true
                    newCapacity = 35
                value = Arrays.copyOf("", 35)
    str.getChars(0, 35, "", 35)
    return this
sb.build() -> "12345678901234567890123456789012345"
sb.capacity() -> 35

请注意,区别在于if (newCapacity - minimumCapacity &lt; 0) 行。如果附加的字符串长度超过oldCapacity * 2 + 2,则newCapacity 将设置为要附加的字符串的长度。

换句话说,在追加时,如果缓冲区不足以容纳现有文本和追加的文本,它会检查(大致)加倍大小是否能容纳新文本。如果这仍然不够,而不是递归扩展,它将扩展到完全足够大。

这不仅发生在 35 上,尽管字符串比这长得多,但您可能不会遇到您追加的内容是当前容量的两倍以上的情况。

如果你这样做,你也会看到相同的“长度 = 容量”

StringBuffer sBuffer = new StringBuffer();
sBuffer.append("1234567890123456");
System.out.println(sBuffer.capacity()); // 16
sBuffer.append("1234567890123456789"); 
System.out.println(sBuffer.capacity()); // 35

但不是

StringBuffer sBuffer = new StringBuffer();
sBuffer.append("1234567890123456");
System.out.println(sBuffer.capacity()); // 16
sBuffer.append("123456789012345678"); 
System.out.println(sBuffer.capacity()); // 34
sBuffer.append("1"); 
System.out.println(sBuffer.capacity()); // 70

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多