在Java中调整ArrayList的大小时,无法理解溢出的可能性

时间:2011-12-19 06:22:31

标签: java arraylist resize

来自JDK 7 java.util.ArrayList类的引用代码段让我感到困惑。我不能为我的生活理解它怎么可能导致溢出。我困惑的地方标有<--- what do they mean by this?。有人可以帮助我理解这种逻辑可能溢出的情况吗? TIA。

public void ensureCapacity(int minCapacity) {
    if (minCapacity > 0)
        ensureCapacityInternal(minCapacity);
}  

private void ensureCapacityInternal(int minCapacity) {
    modCount++;
    // overflow-conscious code <--- what do they mean by this?
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private void grow(int minCapacity) {
    // overflow-conscious code <--- what do they mean by this?
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow <--- what do they mean by this?
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

编辑:我主要担心的是:hugeCapacity如何获得负面大小?

5 个答案:

答案 0 :(得分:2)

当计算值大于其类型允许的字节数时,会产生溢出。

在对oldCapacity执行某些操作后,将值分配给newCapacity,如果这些操作导致某些值不适合int,则会发生溢出。我想这就是为什么这段代码被评为溢出的有趣代码。

答案 1 :(得分:1)

OutOfMemoryError()(在ArrayList中)被抛出2个条件:

  1. minCapacity小于零。这意味着无法创建内存数组分配,即elementData数组大小不能小于零。
  2. 阵列的容量超过了VM内存堆空间。 VM无法创建内存(grow())以在阵列中分配更多对象。
  3. 因此hugeCapacity()确保安全地分配内存的原因。


    grow()hugeCapacity()仅在ensureCapacityInternal()内使用,因此可以说minCapacity < 0是不必要的。我相信这是一个安全检查,只是为了使阵列安全增长。任何差异,而不是抛出错误。

答案 2 :(得分:0)

我怀疑此代码可能在某些时候被修改为使用array.length为long的数组。 (当然,这不是普通的Java ......正如我们所知道的那样。)

答案 3 :(得分:0)

我发现minCapacity < 0的情况。假设有两个长大小的ArrayLists,当你将一个加到另一个时,size + numNew会溢出。

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

例如,下面的代码将抛出OutOfMemoryError。

int oneSize = Integer.MAX_VALUE - 16;
int twoSize = oneSize >> 1;
List<Byte> one = new ArrayList<>(oneSize);
for (int i = 0; i < oneSize; i++) {
    one.add((byte) 1);
}
List<Byte> two = new ArrayList<>(twoSize);
for (int i = 0; i < twoSize; i++) {
    two.add((byte) 2);
}

one.addAll(two);

答案 4 :(得分:0)

关于数字的表示。如果Integer.MAX_VALUE加1,则它将为负数,即2147483648。因此,如果数组足够大,我们再次对其进行扩展将导致minCapacity小于0。