在以下代码中......
StringBuffer buf = new StringBuffer("Is is a far, far better thing that i do");
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
buf.setLength(60);
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
buf.setLength(30);
System.out.println("buf = "+ buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
...输出是:
buf = Is is a far, far better thing that i do
buf.length() = 39
buf.capacity() = 55
buf = Is is a far, far better thing that i do
buf.length() = 60
buf.capacity() = 112
buf = Is is a far, far better thing
buf.length() = 30
buf.capacity() = 112
答案 0 :(得分:2)
致电setLength(60)
会导致ensureCapacity(60)
被称为 1 。
ensureCapacity
依赖于"数组加倍"这意味着它每次需要增加时(至少)将容量加倍。精确的定义记录在the Java Doc for ensureCapacity
:
确保容量至少等于指定的最小值。如果当前容量小于参数,则分配具有更大容量的新内部阵列。新容量是更大的:
- minimumCapacity参数。
- 旧容量的两倍加上2.
如果minimumCapacity参数为非正数,则此方法不执行任何操作,只返回。
在您的特定情况下,第二个表达式(以粗体显示)大于请求的容量,因此将使用此表达式。由于2 * 55 + 2等于112,这就是新容量的含义。
相关问题:
1)实际上,它会调用 extendCapacity ,但其行为与确保容量相同。
答案 1 :(得分:2)
StringBuffer
在方法expandCapacity
的几个点调用。如果它不会超大容量,则每次更改Stringbuffer
s值时都必须分配一个新数组。所以这是一种性能优化。
从手册:
的ensureCapacity
public void ensureCapacity(int minimumCapacity)
确保容量至少等于指定的最小值。 如果当前容量小于参数,那么新的内部 数组分配的容量更大。新的容量是 更大的:
* The minimumCapacity argument. * Twice the old capacity, plus 2.
如果minimumCapacity参数为非正数,则此方法为no 行动,只是返回。
参数: minimumCapacity - 最小所需容量。
答案 2 :(得分:2)
考虑如何使用StringBuffer。当我们需要存储在StringBuffer中的String超过当前容量时,当前容量会增加。如果算法只将容量增加到所需的数量,那么StringBuffer将是非常低效的。 例如:
buf.append(someText);
buf.append(someMoreText);
buf.append(Another100Chars);
可能要求连续三次增加容量。每次容量增加时,底层数据结构(数组)需要在内存中重新分配,这涉及从堆中分配更多RAM,复制现有数据,然后最终垃圾收集先前分配的内存。为了减少这种情况发生的频率,StringBuffer将在需要时将其容量加倍。算法将容量从n移动到2n + 2。以下是AbstraceStringBuilder的源代码,其中实现了此方法:
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
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);
}
每次附加到StringBuffer或调用setLength时,都会调用此方法:
public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
}
}
答案 3 :(得分:1)
这是“阅读免费手册”的情况。来自StringBuffer的Javadoc -
public StringBuffer(String str)
构造一个初始化为指定字符串内容的字符串缓冲区。该 字符串缓冲区的初始容量是16加上字符串参数的长度。
这解释了为什么它最初是55.然后
public void ensureCapacity(int minimumCapacity)
确保容量至少等于指定的最小值。 如果当前容量小于参数,那么新的内部 数组分配的容量更大。新的容量是 更大的:
•minimumCapacity参数。
•旧容量的两倍加上2.
如果minimumCapacity参数是 nonpositive,此方法不采取任何操作,只是返回。
解释为什么它会变为112。
答案 4 :(得分:0)
public synchronized void setLength(int newLength) {
super.setLength(newLength);
}
in super:
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
....
然后:
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
....
最后:
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
....