ArrayList源码:
首先,新增一个元素时,会调用ensureCapacityInternal函数,传入当前需要的大小,确定是否需要扩容。
- /**
- * Appends the specified element to the end of this list.
- *
- * @param e element to be appended to this list
- * @return true (as specified by {@link Collection#add})
- */
- public boolean add(E e) {
- ensureCapacityInternal(size + 1); // Increments modCount!!
- elementData[size++] = e;
- return true;
- }
size是成员变量,默认为0
- /**
- * The size of the ArrayList (the number of elements it contains).
- *
- * @serial
- */
- private int size;
然后调用calculateCapacity确定当前需要的最小容量,调用ensureExplicitCapacity进行扩容
- private void ensureCapacityInternal(int minCapacity) {
- ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
- }
- private static int calculateCapacity(Object[] elementData, int minCapacity) {
- // 如果还没有扩容过,获取DEFAULT_CAPACITY(默认值10)与minCapacity的最大值
- if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
- return Math.max(DEFAULT_CAPACITY, minCapacity);
- }
- return minCapacity;
- }
modCount为AbstractList的成员变量,为扩容的次数
1.当我们要 add 进第 1 个元素到 ArrayList 时,elementData.length 为 0 (因为还是一个空的 list),因为执行了 ensureCapacityInternal()
方法 ,所以 minCapacity 此时为 10。此时,minCapacity - elementData.length > 0
成立,所以会进入 grow(minCapacity)
方法。
2.当 add 第 2 个元素时,已经扩容过了,calculateCapacity直接返回minCapacity ,也就是 2。
此时 elementData.length(容量)在添加第一个元素后扩容成 10 了。此时,minCapacity - elementData.length > 0
不成立,所以不会进入 (执行)grow(minCapacity)
方法。
- private void ensureExplicitCapacity(int minCapacity) {
- modCount++;
-
- // overflow-conscious code
- // 如果第一次list的长度没有指定,minCapacity将为10
- // 初始化时,elementData.length默认为0,第一次添加元素就会扩容
- if (minCapacity - elementData.length > 0)
- grow(minCapacity);
- }
进入核心函数grow():
- private void grow(int minCapacity) {
- // oldCapacity为旧容量,newCapacity为新容量
- int oldCapacity = elementData.length;
- //将oldCapacity 右移一位,其效果相当于oldCapacity /2,
- //我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- // 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,
- //如果minCapacity大于最大容量,则新容量则为`Integer.MAX_VALUE`,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- // minCapacity is usually close to size, so this is a win:
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
注意,如果容量为奇数,右移一位会把小数丢掉,11+11/2 = 21
最后进入Arrays.copyOf()方法:
- public static
T[] copyOf(U[] original, int newLength, Class extends T[]> newType) { - @SuppressWarnings("unchecked")
- T[] copy = ((Object)newType == (Object)Object[].class)
- ? (T[]) new Object[newLength]
- : (T[]) Array.newInstance(newType.getComponentType(), newLength);
- System.arraycopy(original, 0, copy, 0,
- Math.min(original.length, newLength));
- return copy;
- }
这里 主要是创建了一个我们需要的容量的数组copy,然后把原数组的值辅助到copy中,再返回
进入System.arraycopy()方法:
- /**
- * 复制数组
- * @param src 源数组
- * @param srcPos 源数组中的起始位置
- * @param dest 目标数组
- * @param destPos 目标数组中的起始位置
- * @param length 要复制的数组元素的数量,所以传入的是Math.min(original.length, newLength)
- */
- public static native void arraycopy(Object src, int srcPos,
- Object dest, int destPos,
- int length);