结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。
一. 明确类内部重要变量含义
1:数组默认长度
2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_ELEMENTDATA。因为它是静态常量,可以共享这个数组,避免内存浪费。
3:也是一个共享的空数组实例,用于未指定容量的 ArrayList。当你创建一个 ArrayList 但没有指定容量,比如 new ArrayList<>()。它和 EMPTY_ELEMENTDATA 不同的地方在于,一旦向 ArrayList 添加第一个元素,它的容量会自动扩展到默认10的大小。可以达到延迟分配的作用。
4:elementData 是 ArrayList 的实际存储数组,其中保存着所有的元素。如果 ArrayList 是空的,那么 elementData 会指向 EMPTY_ELEMENTDATA 或 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,根据是否指定了容量。
5:ArrayList的实际长度
二. 初始化方式即elementData指向(源码)
第 1 种初始化方式,不指定长度,会指向默认长度的空数组。
第 2 种初始化方式,明确指定长度为0,会指向空数组。
3. 通过add方法来展示扩容过程
3.1 小于默认长度10的扩容
如图所示最后一段是若扩容最小长度小于10或数组长度为0,则会直接扩容为默认长度10.
3.2 大于10的扩容
源码中赋予新长度的的两种增长方式,图中标出的增长1与增长2。
增长1:即为目前数组最少需要的扩容多少
增长2:为原始数组长度的0.5倍。(oldCapacity>>1,代表右移位操作,oldCapacity>>1 等于 oldCapacity/2 等于 oldCapacity*0.5)
源码中是将增长1和增长2传入ArraySupport.newLength函数中来获得合适的新长度。
而ArraySupport.newLength函数中重要公式如下:
可以看出,若扩容0.5个oldCapacity 比需要的最小容量则按照0.5个oldCapacity扩容,否则按照所需的最小容量进行扩容。
4.总结:若首次扩充长度不足10的,扩充为默认最小长度10。超过10的按照实际长度扩容。非首次扩容,若扩容1.5倍够用则按照1.5倍扩容,不够用则按照所需的容量扩容。
补充知识点:为什么扩容倍数是1.5而不是其他倍数。若倍数太大,则可能会导致过多空间浪费,若倍数太小,则会导致频繁扩容,降低性能。所以选择1.5倍尽可能不浪费过多空间,也尽可能不会频繁扩容。