我注意到该capacity方法返回StringBuilder容量......有时它的值等于字符串长度,有时它更大......
是否有一个方程式可以知道它的逻辑是什么?
我注意到该capacity方法返回StringBuilder容量......有时它的值等于字符串长度,有时它更大......
是否有一个方程式可以知道它的逻辑是什么?
我将尝试用一些例子来解释这一点。
public class StringBuilderDemo {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
System.out.println(sb.length());
System.out.println(sb.capacity());
}
}
length()- 构建器中字符序列的长度,因为此字符串构建器不包含任何内容,所以它的长度将为 0。
capacity()- 已分配的字符空间数。当您尝试构造一个内容为空的字符串生成器时,默认情况下它会将初始化大小设为长度+16,即 0+16。所以容量会在这里返回 16。
注意:由 capacity() 方法返回的容量始终大于或等于长度(通常大于),并且会根据需要自动扩展以适应对字符串构建器的添加。
容量函数背后的逻辑:
当您附加到 时StringBuilder,会发生以下逻辑:
if (newCount > value.length) {
expandCapacity(newCount);
}
其中newCount是所需的字符数,value.length是缓冲区的当前大小。
expandCapacity只是增加了背衬的大小char[]
该ensureCapacity()方法是调用的公共方式expandCapacity(),其文档说:
确保容量至少等于指定的最小值。如果当前容量小于参数,则分配具有更大容量的新内部数组。新容量是以下两者中的较大者:
- minimumCapacity 参数。
- 旧容量的两倍,加上 2。
如果 minimumCapacity 参数为非正数,则此方法不执行任何操作并简单地返回。
此函数的作用与您的预期不同 - 它为您提供了此 StringBuilder 实例内存此时可以容纳的最大字符数。
逻辑如下:如果你定义了一个StringBuilder没有构造函数的类的新实例,就像这样new StringBuilder();,默认容量是 16。构造函数可以是 anint或 a String。对于String构造函数,默认容量是这样计算的
int newCapacity = string.length() + 16;
对于int构造函数,容量是这样计算的
int newCapacity = intSpecified + 16;
如果一个新String的附加到了StringBuilder并且新的长度String大于当前容量,那么容量计算如下:
int newCapacity = (oldCapacity + 1) * 2;
从 API:
每个字符串生成器都有容量。只要字符串构建器中包含的字符序列的长度不超过容量,就不需要分配新的内部缓冲区。如果内部缓冲区溢出,它会自动变大。
每当您追加某些内容时,都会检查以确保更新的 StringBuilder 不会超出其容量,如果超出,则调整 StringBuilder 的内部存储大小:
int len = str.length();
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount);
当向其中添加超过其容量的数据时,将根据以下公式重新调整大小:
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
有关详细信息,请参阅src.zipJDK 附带的文件。(以上摘自 1.6 JDK 的片段)
编辑:道歉 - 以下是关于 .NET 的 StringBuilder 的信息,与原始问题并不严格相关。
http://johnnycoder.com/blog/2009/01/05/stringbuilder-required-capacity-algorithm/
StringBuilder 为您可能添加到其中的子字符串分配空间(很像 List 为其包装的数组创建空间)。如果您想要字符串的实际长度,请使用 StringBuilder.Length。
在 Java 1.8 中
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) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
例如 :
StringBuilder str = new StringBuilder();
System.out.println(str.capacity()); //16
str.append("123456789012345");
System.out.println(str.capacity()); //16
str.append("12345678901234567890");
System.out.println(str.capacity()); // 15 + 20 = 35
您可以进入 JDK 代码,看看它是如何工作的,它基于一个 char 数组:new char[capacity],它的工作方式类似于ArrayList(何时使用 LinkedList 而不是 ArrayList?)。两者都使用数组来提高硬件效率,诀窍是分配一大块内存并在其中工作,直到内存不足并需要下一个大块继续(扩展/增长)。