这里阅读的是JDK8的源码,使用无参构造函数的话是创建一个空数组,第一次调用add方法是才生成一个大小为10的数组。
-
执行add方法,会先调用ensureCapacityInternal(size+1)方法,执行完毕后elemData[size++]=e,返回布尔类型。
-
ensureCapacityInternal()方法内部是一个嵌套方法,外层是调用ensureEplicitCapacity(),它的参数为calculateCapacity(),calculateCapacity的作用是检测此时数组是否为空(即是否是首次添加数据),返回10(定义的默认容量)与参数的最大值给外层ensureEplicitCapacity()方法.
-
ensureEplicitCapacity()方法中有一个if判断minCapacity是否大于现在的数组长度,是则扩容,执行grow()方法。
-
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方法生成新扩容后的数组
-
hugeCapacity方法先判断是否minCapacity小于0,如果是那么抛出oom异常, 否则如果minCapacity比MAX_ARRAY_SIZE小返回MAX_ARRAY_SIZE,否则返回Integer.MAX_VALUE。
ensureCapacity()方法。
我们可以在ArrayList类中看到这样一个方法,它并没有被ArrayList自身的其他方法调用过,显示是留给用户(程序员)调用的。
可以在进行多次add方法前先用此方法扩容,一步到位,避免之后频繁触发扩容,影响效率