private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
看过 Arraylist 代码的小伙伴是不是看到这个总会有疑惑:
- 为什么 MAX_ARRAY_SIZE 是等于 Integer.MAX_VALUE - 8,为啥不是-16或者其他数字。
我看了很多回答,他们总是把这个 十进制的8 和 java的对象头联系在一起说,我到现在都不能理解这两个怎么画等号的。
思索了很久,再结合源码的注释,我开始想是不是兄弟们把这个问题想复杂了啊。
注释清清楚楚写着:Some VMs(一些VM)在数组中会有保留字,尝试分配更大的数组可能会导致OutOfMemoryError。
所以这个 Integer.MAX_VALUE - 8 其实是为了保证这些(Some VMs)减少报错的几率(?)
这里我们打个问号,下面我们分析分析。
这个变量只在 grow() 和 hugeCapacity() 两个方法里面用到了。
先看看 grow() 方法:
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);
}
里面第二个if里面会判断 newCapacity 是否大于了 MAX_ARRAY_SIZE,大于了就调用 hugeCapacity() 方法。
再看看 hugeCapacity() 方法:
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
为什么第一个if判断 minCapacity 小于 0 就是代表溢出,minCapacity 什么时候会溢出了,就是当我们的数组已经达到 Integer 的最大值 2^31-1 的时候,他增加一个元素后, 即 minCapacity 等于 2^31 时,这个数从二进制变成十进制就是个负数,所以直接判断 minCapacity 是否小于 0 就能判断是否溢出了。
我再强调一下几个变量的意义:
- newCapacity :预计扩容后的数组长度。
- minCapacity : 原数组增加元素后需要的数组长度。
- MAX_ARRAY_SIZE : Integer.MAX_VALUE - 8
看到return里面的三元表达式,再结合 grow() 方法里面的第二个if判断,思路是不是清晰起来了。
- 首先 预计扩容后的数组长度(newCapacity) 大于了 MAX_ARRAY_SIZE。
- 再判断 原数组增加元素后需要的数组长度(minCapacity ) 是不是大于 MAX_ARRAY_SIZE。
- 如果大于了 MAX_ARRAY_SIZE,那还是会将 预计扩容后的数组长度(newCapacity) 置为 Integer.MAX_VALUE。
- 如果不大于 MAX_ARRAY_SIZE ,则将 预计扩容后的数组长度(newCapacity) 置为 MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)。
你会发现他依旧可能会扩容到 Integer.MAX_VALUE,所以我们可以得知:
Arraylist 的最大容量依旧是 Integer.MAX_VALUE ,而不是 Integer.MAX_VALUE - 8。
很多人看到 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 这句代码,就说 Arraylist 的最大容量是 Integer.MAX_VALUE - 8 ,这是不对的。
到这里可能还会有人会接着问,那最后都是会到 Integer.MAX_VALUE ,那用一个 MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8) 做判断有啥意义。
所以我这里就有了文章开始的那些猜测,这个 MAX_ARRAY_SIZE 值只是为了保证这些(Some VMs)减少报错的几率的。
如果没有这个 MAX_ARRAY_SIZE 的话,这些(Some VMs)在 数组长度为 Integer.MAX_VALUE 的 2/3 左右的时候,一旦触发扩容,newCapacity 直接大于 Integer.MAX_VALUE - 8,然后报错 。
如果有了 MAX_ARRAY_SIZE 的话,那么这些(Some VMs)会在 数组长度为 Integer.MAX_VALUE - 8 的时候,再增加元素才会报错,其他VM会正常的扩容到 nteger.MAX_VALUE。
这样极大的减少了这些(Some VMs)的报错几率。并且为这些(Some VMs)增加了接近1/3的实际储存容量。
最后说明,以上绝大部分都是我的推理,我至此也没查到为啥一定是 8 这个数字,我只能想到这个十进制的8代表二进制数组的最后四位为0,除此之外我并不晓得在这里的具体含义。
望大家一起探讨探讨。