为什么在以下示例中容量更改为112?

时间:2012-03-21 10:31:10

标签: java stringbuffer

在以下代码中......

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

5 个答案:

答案 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;
....