对于ArrayList,顾名思义,称之为数组列表。要明白,它的底层结构是数组,也就是说,ArrayList存储的元素其实是放在了它内部的一个数组中,对ArrayList的操作,其实就是对它内部这个数组的操作。接下来,我们从它的属性,构造器,方法三个方面来分析源码。
1.ArrayList的属性
/** * Default initial capacity. */
//默认的初始容量 private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. */
//一个空数组,当创建无参ArrayList时,底层数组默认的就是这个 private static final Object[] 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 == EMPTY_ELEMENTDATA will be expanded to * DEFAULT_CAPACITY when the first element is added. */
//存放元素的底层数组,此数组的长度也就是数组列表的容量 private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * * @serial */
//ArrayList的大小,也就是它存储元素的个数
private int size;
2.构造器
/** * 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 */
//构造一个ArrayList,并指定初始容量initialCapacity public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** * Constructs an empty list with an initial capacity of ten. */
//构造一个ArrayList,它初始容量是默认的,为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 */
//构造一个ArrayList,并将指定的集合中的元素放到这个数组列表中 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); }
3.方法
add(E e) :将指定的元素添加到列表的尾部
add方法的逻辑如下:
(1).保证数组长度大于等于数组中的现有元素个数+1,这样才能添加下一个元素
(2).然后将修改次数+1,如果不能满足(1)中的条件,那么就需要进行扩容,创建一个新数组,其长度是原来数组的1.5倍,同时把原来数组中的元素都拷贝到新数组中。
public boolean add(E e) {
//确保ArrayList容量大于等于现有的元素个数+1 ensureCapacityInternal(size + 1); // Increments modCount!!
//将元素添加到数组的尾部 elementData[size++] = e; return true; }
private void ensureCapacityInternal(int minCapacity) {
//获取期望得到的ArrayList容量 if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
private void ensureExplicitCapacity(int minCapacity) { modCount++; //修改次数+1 // overflow-conscious code
//如果期望的到的ArrayList容量大现在的ArrayList容量,那么就扩容,就是创建一个长度更大的数组,然后将原来数组中的元素拷贝到新数组中,这个新数组作为ArrayList的底层数组
//需要理解的是:ArrayList的容量也就是它底层数组的长度,ArrayList的大小size是指它存储元素的个数;这两个概念要清楚 if (minCapacity - elementData.length > 0)
//扩容操作 grow(minCapacity); }
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win:
//将原来数组中的元素拷贝到新数组中,新数组的长度是newCapacity elementData = Arrays.copyOf(elementData, newCapacity); }
add(int index,E element) : 将指定元素插入到此列表中的指定位置
由这个方法,我们可以明白对于ArrayList,插入的效率比较低的原因,因为从index位置开始的元素都整体往后一个单位进行拷贝。同理,删除操作效率较低也是类似的原因。
public void add(int index, E element) {
//检查index,是否越界 rangeCheckForAdd(index); //确保数组长度够用 ensureCapacityInternal(size + 1); // Increments modCount!!
//通过copy的方式,从下标位置是index开始到最后一个元素,整体后移1个单位 System.arraycopy(elementData, index, elementData, index + 1, size - index);
//把指定元素插入index位置 elementData[index] = element; size++; }
remove(int index):移除此列表中指定位置的元素
public E remove(int index) {
//检查是否越界 rangeCheck(index); //修改次数+1 modCount++;
//指定位置的元素 E oldValue = elementData(index); //要移动的元素个数 int numMoved = size - index - 1; if (numMoved > 0)
//通过copy的方式,将index+1位置开始的元素整体向前移动一个单位(其实是拷贝) System.arraycopy(elementData, index+1, elementData, index, numMoved);
//将最后一个元素位置的值设置为null,然后元素个数-1 elementData[--size] = null; // clear to let GC do its work return oldValue; }
set(int index,E element):将指定元素替换此列表中指定位置的元素
public E set(int index, E element) { rangeCheck(index); //获取指定位置的元素,被替换后,并返回 E oldValue = elementData(index); elementData[index] = element; return oldValue; }
remove(Object o):移除此列表中首次出现的元素
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++)
//找到指定元素的下标位置 if (o.equals(elementData[index])) {
//移除操作 fastRemove(index); return true; } } return false; }
private void fastRemove(int index) {
//修改次数+1 modCount++;
//需要移动的元素的数量 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 }
addAll(int index,Collection<? extends E> c):从指定的位置开始,将collection中的元素插入到此列表中
public boolean addAll(int index, Collection<? extends E> c) { //判断index是否越界
rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length;
//确保数组长度够用,不够就扩容 ensureCapacityInternal(size + numNew); // Increments modCount //经过以下两次copy操作就可以把collection中的元素全部插入到列表中 int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }
总结:ArrayList的特点是查询效率高,增加和删除效率低,因为它的底层结构是数组。此外,它不是线程安全的。