ArrayList源码分析

ArrayList

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

ArrayList继承于AbstractList,实现了List, RandomAccess, Cloneable, Serializable接口。

RandomAccess 这个接口中并没有任何方法,这个接口仅做为可以快速访问的标志。

构造函数:

    /**
     * 使用指定的初始容量值构造一个空的list。
     *
     * @param  initialCapacity   list 的初始容量
     * @throws IllegalArgumentException  如果指定的initialCapacity是负数就抛出该错误
     */
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);
        }
    }

    /**
     * 使用默认的初始值10来构造一个空的list
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /** 使用指定集合的元素按照其顺序构造一个list,
     * @param c 元素被放入list 的集合集合 
     * @throws NullPointerException 如果指定的集合是null抛出该错误 
     */
    public ArrayList(Collection c) {
        elementData = c.toArray();
        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 {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

/**
 * 在list 的尾部添加一个指定的元素
 *
 * @param e 在list中添加的元素
 * @return true (as specified by {@link Collection#add}) 添加成功后返回true 
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

在add方法中,首先调用了ensureCapacityInternal(size + 1);方法。作用是确保list的空间足够。

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
transient Object[] elementData; // non-private to simplify nested class access

其中又调用了计算容量的方法calculateCapacity()

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

该方法是判断elementData是否为空,如果为空,则将默认容量与传入的数值比较,返回一个较大的数值。如果elementData不为空,则返回传入的数值。

ensureExplicitCapacity方法如下:

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
modCount用于记录对象的修改次数,比如增、删、改,也基本存在于非线程安全的集合类中

如果传入的数值比elementData要大,那么就需要对数组进行扩容。

扩容机制:

grow方法

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
 * 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
 * 虚拟机分配数组的时候会保留一些关键字,因此尝试分配空间的时候会造成oom错误。
 */
private void grow(int minCapacity) {
    // overflow-conscious code  溢出-感知代码
    int oldCapacity = elementData.length; 
    int newCapacity = oldCapacity + (oldCapacity >> 1);  // 右移一位,相当于除以2,这里就是新的容量等于原来容量的3/2
    if (newCapacity - minCapacity < 0)                                     // 如果得到的新数值小于0,说明存在溢出
        newCapacity = minCapacity;                                             // 那么新容量就等于传入的数值
    if (newCapacity - MAX_ARRAY_SIZE > 0)                                 // 如果新容量比MAX_ARRAY_SIZE要大
        newCapacity = hugeCapacity(minCapacity);                 // 
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);// 复制一个 newCapacity 大小的新数组。
}
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow                                // 如果产生溢出
        throw new OutOfMemoryError();                                // 抛出OutOfMemoryError
    return (minCapacity > MAX_ARRAY_SIZE) ?                    // 没有溢出,如果minCapacity大于MAX_ARRAY_SIZE就返回Integer.MAX_VALUE
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

在指定位置插入元素

/**
 * 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);            //检查index 是否合法

    ensureCapacityInternal(size + 1);  
    System.arraycopy(elementData, index, elementData, index + 1,size - index);
    elementData[index] = element;
    size++;
}
public static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);

src : 原数组

srcPos : 原数组指定位置(指定位置开始)

dest : 目标数组

destPos : 目标数组指定位置(指定位置开始)

length : 移动的元素数量

arraycopy.png

/**
 * 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);                                            // 检查index,如果大于list的长度则抛出IndexOutOfBoundsException异常

    modCount++;
    E oldValue = elementData(index);                // 将该数据取出,存放于oldValue

    int numMoved = size - index - 1;                // 数组要移动元素的个数
    if (numMoved > 0)                                                // 如果要移动的元素个数大于0
        System.arraycopy(elementData, index+1, elementData, index,    
                         numMoved);                    // 调用System.arraycopy方法进行复制数组
    elementData[--size] = null; // clear to let GC do its work    让GC去清理

    return oldValue;
}

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

就是先检查index,然后直接对数组进行修改,赋值。

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

直接访问数组下标

主动扩容

/**
 * Increases the capacity of this ArrayList instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 *
 * @param   minCapacity   the desired minimum capacity
 */
public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?0: DEFAULT_CAPACITY;
  // 空表就给minExpand赋值为0,否则赋值为默认容量
    if (minCapacity > minExpand) {            // 判断是否大于minCapacity,是否继续扩容,与上面的扩容机制是一致的
        ensureExplicitCapacity(minCapacity);
    }
}

与linkedlist 的区别

linkedlist 是链表结构,链表就不存在扩容问题。链表的结构特点注定linkedlist是删除和插入操作快,而读速度慢。

而ArrayList 就很适合与读操作,但是进行插入删除就很慢。在不进行扩容的情况下,在list的尾部进行插入操作还是很快的。

线程是否安全

线程不安全。

可以使用Vector ,Vector很多方法都是经过synchronized关键字进行修饰的,因此在效率上并不是那么理想。可以考虑使用Collections.synchronizedList(new ArrayList());方法来对ArrayList进行包装。

你可能感兴趣的:(arraylist)