ArrayList (JDK8) 源码解析

96
sun_____xin
2018.04.04 15:15 字数 507

ArrayList 源码解析

概述

ArrayList 是一个动态数组,容量可以动态增长。他是线程不安全的,允许元素为null。它的底层数据结构是数组,所以会占用一块连续的内存空间。它实现了List<E>, RandomAccess, Cloneable, java.io.Serializable 接口。RandomAccess 代表List获取了随机访问功能,也就是通过下标获取元素对象的功能。

构造函数分析

定义

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

构造函数

执行完构造函数之后会构建出elementData数组和数量Size

/**
 * 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.
 */
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 修饰表示elementData 不会被序列化, 因为elementData不是每次都是满的,每次都序列化会比较浪费时间
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
 * The size of the ArrayList (the number of elements it contains).
 * 当前元素的数量
 * @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) {
   // 如果初始化容量大于 0 ,就新建一个长度为 initialCapacity 的Object 数组 这里没有修改Size(对比第三个构造)
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) { //如果初始化容量为 0 ,直接将空的对象数组赋值给 elementData
        this.elementData = EMPTY_ELEMENTDATA;
    } else {// 容量小于 0 直接抛出异常
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

/**
 * 默认构造方法,默认容量为10 ,
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
   //将空数组赋值给 elementData
    this.elementData = DEFAULTCAPACITY_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) {
   // 使用Collection.toArray()方法获取到一个对象数组,并复制给elementData
    elementData = c.toArray();
   // size 是集合当前的容量,所以通过别的集合来构造的时候要给size复制
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)//当c.toArray出错的时候没有返回对象数组,
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
/**
 * 根据Class的类型去判断是去new一个对象数组还是去通过反射构造一个泛型数组,同时利用native函数,批量赋值元素至新数组中。 
 */
public static <T,U> 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);
    //利用native函数,批量赋值元素至新数组中
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

常用API分析

增加

add(E e)

/**
 * 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; //在数组末尾增加一个元素,并且修改size
    return true;
}
/**
 * Default initial capacity. 默认初始化容量
 */
private static final int DEFAULT_CAPACITY = 10;
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//通过这个判断是否是使用默认构造函数初始化
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}
//这个方法是用来进行扩容检查的
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;//如果确定要扩容,需要修改modCount  记录修改的次数

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)// 如果传过来的容量大小比初始长度,执行扩容方法
        grow(minCapacity);
}
/**
 * 真正的扩容方法,默认扩容一半
 * 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;
   //新的容量 = 老容量 + 老容量的一半, 右移一位表示除以 2分之1
    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:
   // 调用此方法进行扩容
    elementData = Arrays.copyOf(elementData, newCapacity);
}
/**
 * Copies the specified array, truncating or padding with nulls (if necessary)
 * so the copy has the specified length.  For all indices that are
 * valid in both the original array and the copy, the two arrays will
 * contain identical values.  For any indices that are valid in the
 * copy but not the original, the copy will contain <tt>null</tt>.
 * Such indices will exist if and only if the specified length
 * is greater than that of the original array.
 * The resulting array is of the class <tt>newType</tt>.
 * 
 * 
 */
public static <T,U> 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;
}

add(int index, E element)

添加元素 element 到 index 位置

/**
 * 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!!
   // 将指定下标空出,具体就是将index及其后的元素都往后挪动一位
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
   // 赋值
    elementData[index] = element;
   // 长度加1
    size++;
}

addAll(Collection<? extends E> 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 <tt>true</tt> 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  扩容检查
    System.arraycopy(a, 0, elementData, size, numNew); //拷贝数组完成赋值
    size += numNew;
    return numNew != 0;
}

addAll(int index, Collection<? extends E> c)

添加集合到指定位置

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;
    return numNew != 0;
}

小结:先判断是否越界,是否需要扩容,如果扩容就需要复制数组,然后设置对应下标元素值。如果需要扩容,默认扩容一半,如果一半还不够,那么就用目标的size作为扩容后的容量。扩容成功后,会修改 modCount

删除

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).
 * 移除数组中指定位置的元素,后续元素都要左移,并且下标减一
 * @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;
    //如果大于0说明有元素需要左移,如果等于0,说明移除的是最后一位
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);// index右侧的元素都左移一位,覆盖原来的元素
   //最后一个元素赋值为null,会被GC
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

boolean remove(Object o)

移除指定元素

public boolean remove(Object o) {
    if (o == null) { //如果元素为 null 遍历数组移除第一个null
     // 如果元素不为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 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
}

修改

不会修改modCount,相对增删是高效的操作

/**
 * 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;
}

查询

不会修改modCount,相对增删是高效的操作

E elementData(int index) {
    return (E) elementData[index];
}

/**
 * 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);
}

清空

modCount 会修改

/**
 * Removes all of the elements from this list.  The list will
 * be empty after this call returns.
 */
public void clear() {
    modCount++;

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

    size = 0;
}

总结

  • 在增删改查中,增会导致扩容,会修改modCount,删也会修改,改和查一定不会修改
  • 扩容数组会导致复制数组,批量删除需要找到两个集合的交集然后复制数组操作,所以增和删比较低效,改和查比较高效。

补充

ArrayList 与 Vector 的区别

  • ArrayList是线程不安全的,Vector里面的方法都有synchronized修饰,所以是线程安全的
  • ArrayList扩容是扩充百分之五十,Vector扩容是翻倍的size。
Java 基础
Web note ad 1