ArrayList源码分析

ArrayList

@基于JDK8

ArrayList继承体系结构如下:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayList类主要是继承AbstractList类并实现了List接口,实现Cloneable和Serializable接口使得ArrayList具有克隆和序列化的功能。实现了RandomAccess这个接口的集合是支持 快速随机访问 策略的,如果是实现了这个接口的 List,那么使用for循环的方式获取数据的效率会优于用迭代器获取数据。

主要属性

private static final long serialVersionUID = 8683452581122892189L;

/**
 * Default initial capacity.
 	默认初始容量
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * Shared empty array instance used for empty instances.
 共享空常量数组
 */
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.
 也是共享空常量数组 和上面的区别就是当第一个元素被加入进来的时候它知道如何扩张;在源码中函数add(E e)中的第一行代码中的所在的函数就是这句话的实现。
 */
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.
 
 elementData是个数组,它就是集合存储元素的缓冲区,因此证明ArrayList的底层是一个数组。
 当我们创建一个ArrayList不存储任何元素的时候,集合的默认长度是0,不是10,而是在我们第一次往ArrayList里面添加数据的时候,长度会由0拓展为10
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
 * The size of the ArrayList (the number of elements it contains).
 * size代表的是ArrayList里面存储的元素的实际个数,不是它的长度。
 * @serial
 */
private int size;

构造方法

ArrayList有三个构造方法

1.无参构造函数

/**
 * Constructs an empty list with an initial capacity of ten.
 创建一个空的list,初始容量为10
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

这里会有疑问,DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空数组,然后赋值给了elementData,为何注释说其容量就变成10了呢?其实这里的解释要放在add方法里面,后面会做解释。

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
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
      //如果指定的长度大于0,则创建一个新的指定长度的数组,并把该数组赋值给elementData
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
      //如果指定的长度等于0,则把element赋值为空数组
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

从源码可以看到,就是根据参数的大小作为容量来实例化底层的数组对象,其中对参数的3种情况进行了处理。当参数小于0时,抛异常。当参数等于0时,用空的常量数组对象EMPTY_ELEMENTDATA来初始化底层数组elementData。

3.Collection作为参数的构造函数

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 *创建一个包含指定元素的数组,参数为Collection类型,最终ArrayList里面的元素迭代顺序与Collection中的元素顺序保持一致
 *
 * @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是null,则会抛出NullPointerException的异常*/
    elementData = c.toArray();
  //把elementData的长度赋值给size并判断是否为0,如果不为0,就进行数组拷贝
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // 如果为0,那说明传递进来的集合是个空集合,那就把elementData赋值为空数组
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

从源码可以看到,将容器Collection转化为数组赋给数组elementData,还对Collection转化是否转化为了Object[]进行了检查判断。如果Collection为空,则就将空的常量数组对象EMPTY_ELEMENTDATA赋给了elementData;

Add方法

public boolean add(E e)

/**
 * 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) {
  //进入新的函数,开始进行容量确认工作
  //size此时为0
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
ensureCapacityInternal函数:
private void ensureCapacityInternal(int minCapacity) {
  	//int minCapacity 就是我们传递进来的 size+1=1
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
calculateCapacity函数:
//这个函数用来计算当前的集合的容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      //如果是空集合,就返回默认容量10
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
  //如果不是空数组,就返回实际大小
    return minCapacity;
}
ensureExplicitCapacity函数:
private void ensureExplicitCapacity(int minCapacity) {
  //代表实际修改集合的次数
    modCount++;

    // 如果预期的容量(实际容量+1)大于实际的容量,进行扩容
    if (minCapacity - elementData.length > 0)
      //扩容
        grow(minCapacity);
}
grow函数:
/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 * 增加集合的容量,为了确保能容纳指定minCapacity参数指定的参数数量
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // 实际容量
    int oldCapacity = elementData.length;
  	//扩容1.5倍后的新容量
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果新容量小于实际容量 不采取扩容,把预期容量赋值给新容量即可
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
  	//如果新容量大于最大容量(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);
}

public void add(int index, E element)

/**
 * 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++;
}
rangeCheckForAdd函数
  /**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
      //添加的索引如果大于size或者小于0 抛出异常  注意size比最大索引大1 
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
  

public boolean addAll(Collection c)

/**
 * Appends all of the elements in the specified collection to the end of
 * this list, in the order that they are returned by the
 * specified collection's Iterator.  The behavior of this operation is
 * undefined if the specified collection is modified while the operation
 * is in progress.  (This implies that the behavior of this call is
 * undefined if the specified collection is this list, and this
 * list is nonempty.)
 * 把指定集合的元素按照给定的顺序添加到当前集合中 遍历的顺序跟指定集合中存储的顺序一致
 *
 * @param c collection containing elements to be added to this list
 * @return true if this list changed as a result of the call
 * @throws NullPointerException if the specified collection is null
 */
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    //将a中的所有元素拷贝到数组elementData最后一个元素的后面
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

public boolean addAll(int index, Collection c)

/**
 * Inserts all of the elements in the specified collection into this
 * list, starting at the specified position.  Shifts the element
 * currently at that position (if any) and any subsequent elements to
 * the right (increases their indices).  The new elements will appear
 * in the list in the order that they are returned by the
 * specified collection's iterator.
 *
 * @param index index at which to insert the first element from the
 *              specified collection
 * @param c collection containing elements to be added to this list
 * @return true if this list changed as a result of the call
 * @throws IndexOutOfBoundsException {@inheritDoc}
 * @throws NullPointerException if the specified collection is null
 */
public boolean addAll(int index, Collection<? extends E> c) {
  	//位置有效性检查
    rangeCheckForAdd(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    //添加修改次数以及判断是否需要扩张数组长度
    ensureCapacityInternal(size + numNew);  // Increments modCount
		//计算需要移动的元素数量
    int numMoved = size - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
  	//size增加numNew个
    size += numNew;
    return numNew != 0;
}

get方法

public E get(int index)

由于ArrayList底层是借助于数组来实现,因此,从ArrayList中获取元素就相当简单了。直接利用了数组随机访问能力强的特点。

/**
 * Returns the element at the specified position in this list.
  *返回指定位置的元素
 *
 * @param  index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
  	//位置有效性检查
    rangeCheck(index);

    return elementData(index);
}
rangeCheck函数:
/**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

set方法

public E set(int index, E element)

/**
 * Replaces the element at the specified position in this list with
 * the specified element.
 * 使用指定的元素替换指定位置的元素 并返回旧值
 * @param index index of the element to replace
 * @param element element to be stored at the specified position
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E set(int index, E element) {
  	//位置有效性检查
    rangeCheck(index);
		//记录旧值
    E oldValue = elementData(index);
    //插入新值
    elementData[index] = element;
  	//返回旧值
    return oldValue;
}

remove方法

public E remove(int index)

/**
 * Removes the element at the specified position in this list.
 * Shifts any subsequent elements to the left (subtracts one from their
 * indices).
 * 移除指定位置的元素,把指定位置后面的所有元素往左移动1位,它们的索引全部减1
 * 并返回旧值
 * @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);
    //实际修改次数加1
    modCount++;
    //记录旧值
    E oldValue = elementData(index);
    //需要移动的元素个数
    int numMoved = size - index - 1;
    if (numMoved > 0)
        //执行数组拷贝
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    //此时size还是原始size 先减去1 然后将最后一位索引处的元素置为null,让GC来回收
    elementData[--size] = null; // clear to let GC do its work
		//返回旧值
    return oldValue;
}
rangeCheck函数:
/**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 */
//检查指定的索引是否合法,否则抛出异常
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

public boolean remove(Object o)

/**
 * Removes the first occurrence of the specified element from this list,
 * if it is present.  If the list does not contain the element, it is
 * unchanged.  More formally, removes the element with the lowest index
 * 删除第一次出现的指定元素 如果指定的元素在list中不存在,那么不会对集合修改。更确切的说就是
   删除最小索引的并且与指定元素相同的元素。
 * i such that
 * (o==null ? get(i)==null : o.equals(get(i)))
 * (if such an element exists).  Returns true if this list
 * contained the specified element (or equivalently, if this list
 * changed as a result of the call).
 *
 * @param o element to be removed from this list, if present
 * @return true if this list contained the specified element
 */
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;
}

从源码中可以看到,无论是指定对象o是否为null,都是在ArrayList中找到与此第一个相等的元素的位置,然后调用fastRemove(index)来进行移除;如果没有找到指定对象o的位置,则返回false,表示没有移除成功。

fastRemove函数:
/*
 * Private remove method that skips bounds checking and does not
 * return the value removed.
 */
private void fastRemove(int index) {
    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
}

fastRemove函数没有对index进行有效性检查,以及没有返回移除的旧值。原因就在于既然调用了fastTemove函数,就已经在 remove(Object o)函数中找到了相对应要删除的元素,那么索引也就确认了,索引就不用再去验证非法性了。

public boolean removeAll(Collection c)

/**
 * Removes from this list all of its elements that are contained in the
 * specified collection.
 * 删除该集合中指定集合的全部存在元素,不存在的不操作
 * @param c collection containing elements to be removed from this list
 * @return {@code true} if this list changed as a result of the call
 * @throws ClassCastException if the class of an element of this list
 *         is incompatible with the specified collection
 * (optional)
 * @throws NullPointerException if this list contains a null element and the
 *         specified collection does not permit null elements
 * (optional),
 *         or if the specified collection is null
 * @see Collection#contains(Object)
 */
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}
requireNonNull函数
/**
 * 检查指定的对象引用是否不为空。该方法主要用于对方法和构造函数进行参数验证
 * Checks that the specified object reference is not {@code null}. This
 * method is designed primarily for doing parameter validation in methods
 * and constructors, as demonstrated below:
 * 
 * public Foo(Bar bar) {
 *     this.bar = Objects.requireNonNull(bar);
 * }
 * 
* * @param obj the object reference to check for nullity * @param the type of the reference * @return {@code obj} if not {@code null} * @throws NullPointerException if {@code obj} is {@code null} */
public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
batchRemove函数(批量删除功能)
private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0; //r作为遍历参数数组的索引 w为原数组的索引
    boolean modified = false;
    try {
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}
removeIf函数
@Override
public boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    // figure out which elements are to be removed
    // any exception thrown from the filter predicate at this stage
    // will leave the collection unmodified
    int removeCount = 0;
    final BitSet removeSet = new BitSet(size);
    final int expectedModCount = modCount;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        @SuppressWarnings("unchecked")
        final E element = (E) elementData[i];
        if (filter.test(element)) {
            removeSet.set(i);
            removeCount++;
        }
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }

    // shift surviving elements left over the spaces left by removed elements
    final boolean anyToRemove = removeCount > 0;
    if (anyToRemove) {
        final int newSize = size - removeCount;
        for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
            i = removeSet.nextClearBit(i);
            elementData[j] = elementData[i];
        }
        for (int k=newSize; k < size; k++) {
            elementData[k] = null;  // Let gc do its work
        }
        this.size = newSize;
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    return anyToRemove;
}

clear方法

/**
 * Removes all of the elements from this list.  The list will
 * be empty after this call returns.
 * 删除集合中的所有元素 并把原来的位置对应的元素全部置为null
 */
public void clear() {
    modCount++;

    // clear to let GC do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

sort方法

//对集合进行指定比较器的排序
@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    Arrays.sort((E[]) elementData, 0, size, c);
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

clone方法

/**
 * //返回这个ArrayList实例的浅拷贝。(元素本身不会被复制。)
 * Returns a shallow copy of this ArrayList instance.  (The
 * elements themselves are not copied.)
 *
 * @return a clone of this ArrayList instance
 */
public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

indexOf方法

/**
 * Returns the index of the first occurrence of the specified element
 * in this list, or -1 if this list does not contain the element.
  返回在列表中第一次出现的指定元素的索引,如果不存在,返回-1
 * More formally, returns the lowest index i such that
 * (o==null ? get(i)==null : o.equals(get(i))),
 * or -1 if there is no such index.
 */
public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
          //null用==判断
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

isEmpty方法

/**
 * Returns true if this list contains no elements.
 * 返回这个列表是否没有元素 也就是size是否为0
 * @return true if this list contains no elements
 */
public boolean isEmpty() {
    return size == 0;
}

lastIndexOf方法

/**
 * Returns the index of the last occurrence of the specified element
 * in this list, or -1 if this list does not contain the element.
 	返回在列表中最后一次出现的指定元素的索引,如果不存在,返回-1
 * More formally, returns the highest index i such that
 * (o==null ? get(i)==null : o.equals(get(i))),
 * or -1 if there is no such index.
 */
public int lastIndexOf(Object o) {
    if (o == null) {
        for (int i = size-1; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = size-1; i >= 0; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

retainAll方法

/**
 * Retains only the elements in this list that are contained in the
 * specified collection.  In other words, removes from this list all
 * of its elements that are not contained in the specified collection.
 * 仅保留此列表中包含在指定集合中的元素。换句话说,从该列表中删除指定集合中不包含的所有元素。
 * @param c collection containing elements to be retained in this list
 * @return {@code true} if this list changed as a result of the call
 * @throws ClassCastException if the class of an element of this list
 *         is incompatible with the specified collection
 * (optional)
 * @throws NullPointerException if this list contains a null element and the
 *         specified collection does not permit null elements
 * (optional),
 *         or if the specified collection is null
 * @see Collection#contains(Object)
 */
public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}

toArray方法

/**
 * Returns an array containing all of the elements in this list
 * in proper sequence (from first to last element).
 * 将列表转换为数组
 * 

The returned array will be "safe" in that no references to it are * maintained by this list. (In other words, this method must allocate * a new array). The caller is thus free to modify the returned array. * *

This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this list in * proper sequence */ public Object[] toArray() { return Arrays.copyOf(elementData, size); }

你可能感兴趣的:(Java源码分析)