来自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如何获得负面大小?
答案 0 :(得分:2)
当计算值大于其类型允许的字节数时,会产生溢出。
在对oldCapacity
执行某些操作后,将值分配给newCapacity
,如果这些操作导致某些值不适合int
,则会发生溢出。我想这就是为什么这段代码被评为溢出的有趣代码。
答案 1 :(得分:1)
OutOfMemoryError()
(在ArrayList
中)被抛出2个条件:
minCapacity
小于零。这意味着无法创建内存数组分配,即elementData
数组大小不能小于零。grow()
)以在阵列中分配更多对象。因此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。