ArrayList源码分析

1、成员变量

private static final int DEFAULT_CAPACITY = 10;

private static final Object[] EMPTY_ELEMENTDATA = {};

transient Object[] elementData;

private int size;

/**
 * 有初始化容量的构造参数
 */
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
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

2、get()方法

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

    return elementData(index);
}

// 检查数组下标是否越界
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

E elementData(int index) {
    // 根据索引直接返回数组中的元素
    return (E) elementData[index];
}

3、set()方法

public E set(int index, E element) {
    rangeCheck(index); // 检查数组下标是否越界

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

4、add()方法

/**
 * 在数组末尾插入元素
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}

/**
 * 在指定位置插入元素
 */
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;
    size++;
}

/**
 * 处理数组容量与扩容
 */
private void ensureCapacityInternal(int minCapacity) {

    // 判断是不是默认空数组
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); // 设置容量
    }

    ensureExplicitCapacity(minCapacity);
}

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

    // 判断容量是否大于实际的数组长度
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private void grow(int minCapacity) {
    int oldCapacity = elementData.length; // 老容量
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量 = 老容量 + 老容量的一半
    if (newCapacity - minCapacity < 0)
        // 初始化时newCapacity=0
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0) // 扩容后超过了最大数组容量
    
        // 实际数组的长度+1 > MAX_ARRAY_SIZE 返回Integer.MAX_VALUE否则返回MAX_ARRAY_SIZE
        newCapacity = hugeCapacity(minCapacity); // 最大是Integer.MAX_VALUE
    
    // 复制数组,对多只能复制前Integer.MAX_VALUE个
    elementData = Arrays.copyOf(elementData, newCapacity);
}

5、remove()方法

/**
 * 移除指定位置的元素。将后续元素左移
 */
public E remove(int index) {
    rangeCheck(index); // 索引范围检查

    modCount++;
    E oldValue = elementData(index); // 保存即将删除的元素

    int numMoved = size - index - 1; // 要移动的元素的个数
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // 原数组中的元素被复制后左移,最后一个元素是重复的,要移除

    return oldValue;
}

/**
 * 移除list中第一个匹配的元素,将后续元素左移,如果没找到不做任何变动。
 */
public boolean remove(Object o) {
    if (o == null) {
        // 要删除的元素是null,遍历list,将遇到的第一个null元素删除
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        // 要删除的元素不是null,遍历list,将第一个相等的元素删除
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

/*
 * 私有删除方法,没有索引范围检查,不反返回删除的元素
 */
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
}

6、clear()方法

/**
 * 移除list里的所有元素
 */
public void clear() {
    modCount++;

    // 遍历数组,将每个元素设置成null
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

7、ArrayList和LinkedList比较

1、ArrayList底层数据结构是数组,LinkedList的是链表。

2、随机访问时,ArrayList直接通过索引访问元素;LinkedList只能遍历链表来查找。这种情况下ArrayList的效率比LinkedList效率高。

3、添加删除元素时,ArrayList需要将目标元素后面的所有元素向左或者向右移动1位;LinkedList只需要在两个节点之间插入即可,不需要移动其他元素的位置,这种情况下LinkedList的效率比ArrayList效率高。
posted @ 2018-07-16 18:13  liycode  阅读(131)  评论(0编辑  收藏  举报