Java ArrayList中ensureCapacity方法中使用的逻辑

Java ArrayList中ensureCapacity方法中使用的逻辑,java,Java,我正在浏览ArrayList的源代码。我遇到了ensureCapacity()方法,它增加了内部使用的数据数组的容量。其中,基于逻辑int-newCapacity=(oldCapacity*3)/2+1增加了数据数组的新容量其中旧容量是当前数据数组大小。选择(oldCapacity*3)/2+1作为新数组大小有什么特别的原因吗?如果有,是什么原因 /** * Increases the capacity of this <tt>ArrayList</tt> instan

我正在浏览ArrayList的源代码。我遇到了ensureCapacity()方法,它增加了内部使用的数据数组的容量。其中,基于逻辑
int-newCapacity=(oldCapacity*3)/2+1增加了数据数组的新容量其中旧容量是当前数据数组大小。选择
(oldCapacity*3)/2+1
作为新数组大小有什么特别的原因吗?如果有,是什么原因

/**
 * Increases the capacity of this <tt>ArrayList</tt> instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 *
 * @param   minCapacity   the desired minimum capacity
 */
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
    Object oldData[] = elementData;
    int newCapacity = (oldCapacity * 3)/2 + 1;
        if (newCapacity < minCapacity)
    newCapacity = minCapacity;
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
}
}
/**
*如果需要,请增加此ArrayList实例的容量
*必要时,确保它至少可以容纳元素的数量
*由最小容量参数指定。
*
*@param minCapacity所需的最小容量
*/
公共空间容量(国际最小容量){
modCount++;
int oldCapacity=elementData.length;
如果(最小容量>旧容量){
对象oldData[]=elementData;
int newCapacity=(旧容量*3)/2+1;
if(新容量<最小容量)
新容量=最小容量;
//minCapacity通常接近大小,因此这是一个胜利:
elementData=Arrays.copyOf(elementData,newCapacity);
}
}

提前感谢…

每次调用该列表时,它都会将列表增加50%,以防止过早分配世界。
+1
用于捕捉列表初始斜体化为1:)

JavaDoc中唯一的保证是添加新元素具有恒定的摊销时间。这意味着向数组中添加新元素的平均时间是恒定的。有时可能需要更长的时间(比如在尝试调整数组大小时),但总的来说,这些情况非常罕见,不会对平均值产生太大影响

因此,为了能够尊重这一保证,他们需要确保很少发生调整大小的情况,以免影响平均添加时间。因此,他们将当前容量的百分比用于新容量。如果调整大小类似于
oldCapacity+50
,则数组对于小的ArrayList来说太大,但是如果要添加几千个元素,则每50个元素调整一次大小会降低性能。通过这种方式,容量会成倍增加(如果您已经添加了很多元素,那么很可能您会添加更多元素,因此它们会将容量增加更多),这样就不会太多地降低性能


至于他们选择50%的原因,也许他们觉得将容量增加一倍(或更多)可能是杀伤力过大(对于非常大的ArrayList会消耗太多额外内存),而过低(比如10-25%)可能会降低太多性能(通过执行太多的重新分配),因此+50%可能提供了足够好的性能,不会占用太多额外的内存。我猜他们在确定值之前做了一些性能测试。

我只是查看了Java 6的ArrayList实现,但找不到您提到的那一行。这是来自有效的Java吗?@Helper方法:您的Java impl的供应商是什么?在sun jdk中,我看到了上面提到的行。我使用的是sun jdk 1.6.0-b105。对“+1”部分的解释很好,我是在读了你的建议后才明白的。好吧,但为什么它不是(旧容量*12)/5+1呢?50%的增长背后有什么逻辑吗?@Ronald我想我们的想法是将名单扩大到一个合理的规模。50%显然有点随意。不,+1表示空数组,其中算法将产生0。@Helper方法,容量为1,您认为(int)((1*3)/2)与1不同吗?:)+很好的解释。我认为有效的Jave也谈到了算法,但我现在找不到。谢谢你的解释。我正在研究一个有时间限制的问题,java ArrayList总是失败,而STL vector使用相同的算法成功了。这将我引向这个讨论:Java使用的缩放策略与STL vector使用的不同(它将容量增加了一倍)。我承认容量加倍可能会消耗更多的额外内存,但+50%会导致更频繁的增长(log_2->log_{3/2})。对于每次插入,总的运行时间仍将分摊到O(1),但java ArrayList后面的常量远高于stl vector。知道他们为什么这样做了吗?(oldCapacity*3)/2+1)而不是(oldCapacity*1.5)+1?,因为它需要是一个整数,使用1.5将其转换为双精度。例如,如果oldCapacity为5,第一个公式给出的是5*3=15,15/2=7,7+1=8,而双精度版本给出的是5*1.5=7.5,7.5+1=8.5,这将需要额外的(int)转换来去除小数部分。目前为止最好的解释!!