StringBuffer 的容量是如何增加的?
How is capacity increased in StringBuffer?
我们知道 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
任何人都可以阐明这一点吗?
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
.
具体情况可能与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 < 0)
行。如果追加的字符串长度超过 oldCapacity * 2 + 2
,则 newCapacity
将设置为要追加的字符串的长度。
换句话说,在附加时,如果缓冲区不够大,无法容纳现有文本和附加文本,它将检查(大致)加倍大小是否可以容纳新文本。如果这还不够,它不会递归扩展,而是扩展到正好足够大。
这不仅发生在 35 上,尽管字符串比 35 长得多,但您可能不会 运行 遇到您追加的内容是当前字符串的两倍多的情况容量。
如果你这样做,你也会看到相同的 "length = capacity",比如
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
我们知道 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
任何人都可以阐明这一点吗?
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
.
具体情况可能与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 < 0)
行。如果追加的字符串长度超过 oldCapacity * 2 + 2
,则 newCapacity
将设置为要追加的字符串的长度。
换句话说,在附加时,如果缓冲区不够大,无法容纳现有文本和附加文本,它将检查(大致)加倍大小是否可以容纳新文本。如果这还不够,它不会递归扩展,而是扩展到正好足够大。
这不仅发生在 35 上,尽管字符串比 35 长得多,但您可能不会 运行 遇到您追加的内容是当前字符串的两倍多的情况容量。
如果你这样做,你也会看到相同的 "length = capacity",比如
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