在2010年3月9日,Kevin L. Stern写道:
我进行了一个快速搜索,发现Java确实基于二进制补码。尽管如此,请允许我指出,总的来说,这种类型的代码让我感到担忧,因为我完全期望在某个时候会有人来做Dmytro建议的事情;也就是说,有人会改变:
if (a - b > 0)
至
if (a > b)
整艘船都会沉没。个人而言,我喜欢避免使用晦涩难懂的算法,除非有很好的理由使用整数溢出作为算法的基础。通常情况下,我更喜欢完全避免溢出,并使溢出场景更加明确:
if (oldCapacity > RESIZE_OVERFLOW_THRESHOLD) {
} else {
}
这是一个很好的观点。
在ArrayList
中,我们不能这样做(或者至少不兼容),因为ensureCapacity
是公共API并且已经将负数解释为无法满足的正容量请求。
当前API的使用方法如下:
int newcount = count + len;
ensureCapacity(newcount);
如果你想避免溢出,你需要改变成一些不那么自然的东西,比如
ensureCapacity(count, len);
int newcount = count + len;
无论如何,我会保留对溢出的注意代码,但是增加更多的警告注释,并对大型数组创建进行"轮廓",以便ArrayList
的代码现在看起来像:
public void ensureCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
Webrev 已经重新生成。
Martin
在 Java 6 中,如果您使用 API 如下:
int newcount = count + len;
ensureCapacity(newcount);
如果 newCount
溢出(变为负数),if (minCapacity > oldCapacity)
将返回 false,您可能会错误地认为 ArrayList
增加了 len
。
if (newCapacity - minCapacity < 0)
比if (newCapacity < minCapacity)
更好是因为它避免了在两个大整数相加时可能发生的溢出错误。 - Eran