我正在阅读 Java 的 ArrayList
源代码,并注意到 if 语句中的一些比较。
在 Java 7 中,方法 grow(int)
用途
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
在 Java 6 中,grow
不存在。方法ensureCapacity(int)
然而使用
if (newCapacity < minCapacity)
newCapacity = minCapacity;
改变背后的原因是什么?是性能问题还是风格问题?
我可以想象与零进行比较会更快,但执行完全减法只是为了检查它是否为负数对我来说似乎有点矫枉过正。同样就字节码而言,这将涉及两条指令(ISUB
和 IF_ICMPGE
),而不是一条(IFGE
)。
a < b
和 a - b < 0
可能意味着两种不同的东西。考虑以下代码:
int a = Integer.MAX_VALUE;
int b = Integer.MIN_VALUE;
if (a < b) {
System.out.println("a < b");
}
if (a - b < 0) {
System.out.println("a - b < 0");
}
运行时,只会打印 a - b < 0
.发生的事情是 a < b
显然是错误的,但是 a - b
溢出变成-1
, 是负数。
现在,话虽如此,考虑数组的长度非常接近 Integer.MAX_VALUE
. ArrayList
中的代码是这样的:
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
oldCapacity
真的很接近 Integer.MAX_VALUE
所以newCapacity
(即 oldCapacity + 0.5 * oldCapacity
)可能会溢出并变成 Integer.MIN_VALUE
(即否定)。然后,减去 minCapacity
下溢回到正数。
此检查确保 if
不执行。如果代码写成 if (newCapacity < minCapacity)
,它将是 true
在这种情况下(因为 newCapacity
是负数)所以 newCapacity
将被迫 minCapacity
不管oldCapacity
.
这种溢出情况由下一个 if 处理。当newCapacity
已溢出,这将是 true
: MAX_ARRAY_SIZE
定义为 Integer.MAX_VALUE - 8
和 Integer.MIN_VALUE - (Integer.MAX_VALUE - 8) > 0
是 true
. newCapacity
因此正确处理:hugeCapacity
方法返回 MAX_ARRAY_SIZE
或 Integer.MAX_VALUE
.
注意:这就是 // overflow-conscious code
这个方法中的评论是在说。
我是一名优秀的程序员,十分优秀!