ArrayList多是在开发中使用最多的集合类。ArrayList其实就是一个动态数组,它会根据元素的个数进行动态扩容。java
下面是部分源码,本次源码基于jdk1.7:数组
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; /** * ArrayList默认初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 使用无参构造方法时ArrayList使用的空数组 * Shared empty array instance used for empty instances. */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * ArrayList维护用于存放数据的数组 * */ private transient Object[] elementData; /** * 数组大小 * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size; /** * 构造一个空数组,自定义指定初始容量 * * @param initialCapacity 自定义初始容量 * @throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** * 构造一个空数组,初始容量是10 */ public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } /** * 私用方法用于保证数组容量,先判断数组是否为空,为空则容量最少为10 */ private void ensureCapacityInternal(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } /** * 该方法被调用一次modCount内部修改计数器会加1,modCount计数器被定义在父类AbstractList中 * modCount被内部实现Iterator和ListIterator的类使用 * 该方法考虑了溢出,当须要的容量超过了当前数组的容量开始调用grow方法进行扩容 */ private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * 最大可分配容量 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 该方法用于增长数组的容量,确保可容纳指定的最小长度的元素个数 * 按照数组元容量的1.5倍扩容,这个扩容量主要是综合考虑了扩容次数和内存使用方便考虑的, * 若是扩容倍数大了浪费内存,小了会增长扩容次数增长开销。 * 该方法实际是计算好最终的扩容量而后交给Arrays.copyOf->System.arraycopy * Systeam的arraycopy是一个native的方法实现数组的拷贝生成新的数组 * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //等价于int newCapacity = oldCapacity + oldCapacity/2,即按照当前容量的1.5倍扩容; int newCapacity = oldCapacity + (oldCapacity >> 1); //若是原数组1.5倍容量小于指定的最小容量,则使用指定的最小容量 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //若是原数组1.5倍容量大于MAX_ARRAY_SIZE(ps:Integer.MAX_VALUE - 8),则使用MAX_ARRAY_SIZE作容量 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); } /** * 确保最大容量不能超过MAX_ARRAY_SIZE,超过了直接强制使用MAX_ARRAY_SIZE做为容量 */ private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** * * 添加指定的元素,添加元素前调用ensureCapacityInternal方法来保证容量正常 * 固然每增长一个元素modCount会加1 * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } /** * 它也增长了modCount,而后计算要移动的元素个数,从index日后的元素都往前移动一位, * 实际调用System.arraycopy方法移动元素。elementData[--size] = null; * 这行代码将size减一,同时将最后一个位置设为null方便被回收 * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; } }