ArrayList源码分析
ArrayList是容量可以改变的非线程安全集合。内部实现使用数组进行存储(需要一块内存连续的空间),集合扩容时会创建更大的数组空间,把原有数据复制到新的数组中。
ArrayList支持对元素的快速随机访问,但是插入与删除速度通常很慢(会涉及元素的移动,时间复杂度为O(n))。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; /** * Default initial capacity. 默认初始容量为10 */ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. 创建ArrayList对象时默认内部数组为空 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access /** * The size of the ArrayList (the number of elements it contains). ArrayList集合包含的元素数量 * * @serial */ private int size; /** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) {
// 若给定的初始容量大小合法,则创建一个给定大小的数组 if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } }
添加元素方法:
/** * Appends the specified element to the end of this list. * * @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; } /** * Inserts the specified element at the specified position in this * list. Shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
ensureCapacityInternal:确保容量满足添加条件
private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code
// 如果添加后的数组长度大于现在的数组容量,那么扩容
if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; 旧的数组长度 int newCapacity = oldCapacity + (oldCapacity >> 1); 新的数组长度为旧的数组长度的1.5倍 if (newCapacity - minCapacity < 0) // 正数带符号右移的值肯定是正值,所以oldCapacity + (oldCapacity >> 1)的结果可能超过int可以表示的最大值,反而可能比参数 newCapacity = minCapacity; minCapacity更小,则返回minCapacity 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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
ArrayList是线程不安全的,要使用线程安全的List:
List<?> list = Collections.synchronizedList(new LinkedList<?>());
但是无论是读取还是写入,Collections.synchronizedList都会进行加锁,当我们并发级别特别高,线程之间在任何操作上都会进行等待,因此在某些场景中它不是最好的选择。在很多的场景中,我们的读取操作可能远远大于写入操作,为了将读取的性能发挥到极致,提供了CopyOnWriteArrayList类,该类在使用过程中,读读之间不互斥并且更厉害的是读写也不互斥。