6 回答
TA贡献1821条经验 获得超4个赞
写个简单的例子,楼主调试一下就知道了
public static void main(String[] args) {
int oldCapacity = Integer.MAX_VALUE - 16;
System.out.println(oldCapacity);
int minCapacity = Integer.MAX_VALUE - 15;
int maxSize = Integer.MAX_VALUE - 8;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - maxSize > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
System.out.println(newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > Integer.MAX_VALUE - 8) ?
Integer.MAX_VALUE :
Integer.MAX_VALUE - 8;
}
int newCapacity = oldCapacity + (oldCapacity >> 1);这句执行后如果超过int的最大值那么newCapacity会是一个负数,这个需要了解一下数字二进制的加减原理。
下面这四句就是针对newCapacity溢出变成负数的时候的处理
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - maxSize > 0)
newCapacity = hugeCapacity(minCapacity);
TA贡献1816条经验 获得超6个赞
oldCapacity
等于(Integer.MAX_VALUE-7)/1.5
的时候,也就是newCapacity
等于Integer.MAX_VALUE-7
,执行hugeCapacity
最后得到的newCapacity
是Integer.MAX_VALUE
,已经是数组支持的上限了,下次扩容就会抛OutOfMemoryError
了,楼上你的newCapacity=minCapacity
是怎么得出来的
TA贡献1801条经验 获得超16个赞
当数组要溢出的时候,就加上数组的1/2,然后和数组最大的常量进行比对,如果超出数组的最大size,就新申请一个Integer.MAX_VALUE
的数组,然后把之前旧数组复制过来。
其中最难理解的是>>1
,其实相当于除以2。
TA贡献1803条经验 获得超3个赞
TA贡献2011条经验 获得超2个赞
TA贡献1884条经验 获得超4个赞
我陷入的问题有点钻牛角尖了,或者是理解能力不够。
总结:
数组size值发生溢出,发生在第二个判断 if (newCapacity - maxArraySize > 0) = true时,即size要足够大,我才考虑数组会溢出的问题。
正常情况下,每次size扩容1.5倍。当size扩大1.5倍发生int的溢出时,就每次进行最小扩容(+1)就可以了。第一个判断 if (newCapacity - minCapacity < 0) 这个就是为这个溢出准备的。
还有一个问题:为什么扩容的倍数为1.5 而不选择其他倍数?
//抛异常的情况:
//数组原大小oldCapacity 已经为int的最大值,此时再次调用grow()扩容minCapacity发生溢出,进入hugeCapacity() 抛出异常。 这是size会溢出的情况,只有size大于nteger.MAX_VALUE - 8 时,才开始考虑是不是抛出溢出异常
public static void main(String[] args) {
int maxArraySize = Integer.MAX_VALUE - 8;
int oldCapacity = Integer.MAX_VALUE;
int minCapacity = oldCapacity + 1;
// overflow-conscious code
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 1.5倍扩容大小 - 元素个数
// 正常情况下,1.5倍的扩容 肯定大于 元素个数,肯定不需要频繁的扩容,所以一次来大一点,至于为什么是1.5倍,这个就不知道了。
// 当 1.5倍扩容发生int的溢出时,就每次进行最小扩容(+1)就可以了。
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
//newCapacity大于maxArraySize 才考虑进入这个方法
if (newCapacity - maxArraySize > 0) {
newCapacity = hugeCapacity(minCapacity);
}
System.out.println(newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
{
throw new OutOfMemoryError();
}
return (minCapacity > Integer.MAX_VALUE - 8) ?
Integer.MAX_VALUE :
Integer.MAX_VALUE - 8;
}
}
添加回答
举报