这里阅读的是JDK8的源码,使用无参构造函数的话是创建一个空数组,第一次调用add方法是才生成一个大小为10的数组。

  • 执行add方法,会先调用ensureCapacityInternal(size+1)方法,执行完毕后elemData[size++]=e,返回布尔类型。
    image.png

  • ensureCapacityInternal()方法内部是一个嵌套方法,外层是调用ensureEplicitCapacity(),它的参数为calculateCapacity(),calculateCapacity的作用是检测此时数组是否为空(即是否是首次添加数据),返回10(定义的默认容量)与参数的最大值给外层ensureEplicitCapacity()方法.
    image.png
    image.png

  • ensureEplicitCapacity()方法中有一个if判断minCapacity是否大于现在的数组长度,是则扩容,执行grow()方法。
    image.png

  • grow先根据旧的数组长度生成newCapacity=oldCapacity + (oldCapacity>>1),及扩大1.5倍。实际上是偶数扩大1.5倍,奇数因为会丢失小数略小于1.5倍。然后进行两次if判断,第一个if会判断此时新容量是否足够了,若不够 newCapacity=minCapacity。第二个if判断此时newCapacity是否比最大数组长度(ArrayList中定义的常量MAX_ARRAY_SIZE,它等于整数最大值减8)还要大,如果判断为true,则newCapacity等于hugeCapacity的返回值。前面的语句都顺利执行完毕后,调用Arrays.copy方法生成新扩容后的数组
    image.png

  • hugeCapacity方法先判断是否minCapacity小于0,如果是那么抛出oom异常, 否则如果minCapacity比MAX_ARRAY_SIZE小返回MAX_ARRAY_SIZE,否则返回Integer.MAX_VALUE。
    image.png

ensureCapacity()方法。

我们可以在ArrayList类中看到这样一个方法,它并没有被ArrayList自身的其他方法调用过,显示是留给用户(程序员)调用的。
image.png
可以在进行多次add方法前先用此方法扩容,一步到位,避免之后频繁触发扩容,影响效率

Q.E.D.