ArrayList源码解析

继承体系

这里写图片描述
ArrayList主要是继承自AbstractList抽象类并实现了List接口、实现了Cloneable和Serializable接口使得ArrayList具有克隆和序列化的功能、实现了RandomAccess接口以实现随机访问的功能。

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

重要属性

private static final long serialVersionUID = 8683452581122892189L;

/**
 * 默认的初始容量
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * 一个共享的空的数组实例
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * 一个共享的空的数组实例
 * 与EMPTY_ELEMENTDATA区别在于当第一个元素被加入进来的时候它知道如何扩张
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * 存放元素的数组空间
 * 所以ArrayList其底层是基于数组实现的
 * 用transient修饰,表示不可序列化
 */
transient Object[] elementData; 

/**
 * ArrayList中元素的数量
 */
private int size;

构造函数

/**
 * 无参构造函数
 * 构造一个初始容量为10的空列表
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * 指定初始容量的构造函数
 * 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) {
        // 创建初始数组
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

/**
 * 使用传递的集合初始化List的构造函数
 * 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) {
    // 将集合c转换成数组元素,然后传递给elementData
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        // 检查是否转换为Object[]
        if (elementData.getClass() != Object[].class)
            // 重新转换,进行复制
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        // 使用默认的空的常量数组对象EMPTY_ELEMENTDATA
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

add方法

1.add(E e)

  1. 进行空间检查,决定是否进行扩容,以及确定最少需要的容量
  2. 如果确定扩容,就执行grow(int minCapacity),minCapacity为最少需要的容量
  3. 第一次扩容,逻辑为newCapacity = oldCapacity + (oldCapacity >> 1);即在原有的容量基础上增加一半。
  4. 第一次扩容后,如果容量还是小于minCapacity,就将容量扩充为minCapacity。
  5. 对扩容后的容量进行判断,如果大于允许的最大容量MAX_ARRAY_SIZE,则将容量再次调整为MAX_ARRAY_SIZE。至此扩容操作结束。
/**
 * 添加元素到list末尾
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 */
public boolean add(E e) {
    // 确保数组空间容量足够,容量>size+1
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    // 如果数组为默认的空数组实例DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    // 比较minCapacity与默认初始容量DEFAULT_CAPACITY,设为最大的数
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    // 确保数组空间大于minCapacity
    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    // 定义父类AbstractList中的变量 protected transient int modCount = 0; 
    // 这个变量的主要作用是修饰结构化的修改此List的次数
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        // 扩容
        grow(minCapacity);
}

/**
 * ArrayList的最大容量
 * 减8是因为某些VM会在数组中保留一些头字
 * 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
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
 * 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.5倍扩容
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 如果扩容后的容量依旧小于想要的容量minCapacity,则将扩容容量改为minCapacity 
    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);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    // 如果想要的容量大于MAX_ARRAY_SIZE,则分配Integer.MAX_VALUE,否则分配MAX_ARRAY_SIZE
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

2.add(int index, E element)

  1. 越界检查
  2. 空间检查,如果有需要进行扩容
  3. 插入元素
/**
 * 在指定位置插入元素
 * 当前位置的元素和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位置,将index之后的元素后移一位
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element;
    // 容量加一
    size++;
}

/**
 * 检查下标是否越界
 * A version of rangeCheck used by add and addAll.
 */
private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

3.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
 */
public boolean addAll(Collection<? extends E> c) {
    // 获取添加的集合数组及长度
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    // 将数组a中的元素全部添加到原数组的后面
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

remove方法

  1. 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;
    if (numMoved > 0)
        // 数组中index之后的元素进行左移一位
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
    // 数量减一,并将索引为size-1处的元素置为null,为了进行GC操作,显式的为size-1处位置赋null值
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

/**
 * 检查下标是否越界
 * 下标小于0的判断是在elementData方法中判断的
 * 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));
}

@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}

2.remove(Object o)

/**
 * 移除指定值的元素
 * 返回值为true或false,是否存在指定值的元素
 * 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
 *
 * @param o element to be removed from this list, if present
 */
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;
}

/*
 * 快速删除,跟remove(int index)方法类似,少了越界检查,及返回旧值
 * 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
}

3.removeAll(Collection< ?> c)
retainAll(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
 */
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

/**
 * 移除不在指定集合中出现的元素,只保留在该集合中出现过的元素
 * 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
 * @see Collection#contains(Object)
 */
public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}

/**
 * complement 表示要保留的元素是否在集合c中出现,false表示不出现,true表示出现
 */
private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    // 是否修改成功
    boolean modified = false;
    try {
        // 两个索引进行判断,一快一慢进行移动
        // r为快索引,存放检查到元素的下标,w为慢索引,存放实际保留元素的下标
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)
                // 如果符合保留条件,将该r下标的元素进行保存,放置到w下标上,w++
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        // 防止contains()抛出异常,r下标之后的元素没有判断
        if (r != size) {
            // 将r下标之后的元素移动到w下标之后,并修改w值
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        // 是否移除元素
        if (w != size) {
            // clear to let GC do its work
            // 置w下标之后的元素为空,便于GC清除
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            // 更新size数量
            size = w;
            modified = true;
        }
    }
    return modified;
}

get方法

/**
 * 获取指定位置的元素
 * 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);
}

set方法

/**
 * 设定指定位置的元素,返回旧值
 * 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;
}

序列化

elementData使用transient修饰,即elementData无法被序列化。这样做是因为当我们序列化ArrayList的时候,此时ArrayList中的elementData并不一定是满的,即不一定每个空间都放置了实际数据,所以我们没必要序列化整个elementData。因此ArrayList实现了Serializable接口,重写了writeObject和readObject方法。

/**
 * Save the state of the <tt>ArrayList</tt> instance to a stream (that
 * is, serialize it).
 */
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    // 序列化非transient元素
    s.defaultWriteObject();

    // Write out size as capacity for behavioural compatibility with clone()
    // 序列化数量,为读取反序列化做准备
    s.writeInt(size);

    // Write out all elements in the proper order.
    // 遍历elementData数组,只序列化存在的实际数据元素
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

/**
 * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
 * deserialize it).
 */
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    // elementData设置为空的数组实例 EMPTY_ELEMENTDATA
    elementData = EMPTY_ELEMENTDATA;

    // Read in size, and any hidden stuff
    s.defaultReadObject();

    // Read in capacity
    // 读取数组的实际数据容量
    s.readInt(); // ignored

    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        // 确认容量符合数组空间大小,太小就扩容
        ensureCapacityInternal(size);

        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            // 读取每个元素,并赋值
            a[i] = s.readObject();
        }
    }
}

iterator方法

/**
 * Returns an iterator over the elements in this list in proper sequence.
 *
 * The returned iterator is fail-fast
 * 快速失效,即创建迭代器后,不能在外部手动进行修改原集合,否则该迭代器失效,需重新创建!
 *
 * @return an iterator over the elements in this list in proper sequence
 */
public Iterator<E> iterator() {
    return new Itr();
}

/**
 * 内部类
 * An optimized version of AbstractList.Itr
 */
private class Itr implements Iterator<E> {
    // 迭代器的游标,指向下一个元素的下标,初始值为0
    int cursor;       // index of next element to return
    // 指向当前元素的下标
    int lastRet = -1; // index of last element returned; -1 if no such
    // 修改次数,用于检测迭代过程中进行删除后,前后是否一致
    int expectedModCount = modCount;

    // 是否有下一元素
    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    // 返回下一元素
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        // cursor指向下一位
        cursor = i + 1;
        // 更新lastRet,返回当前指向的元素
        return (E) elementData[lastRet = i];
    }

    // 删除最近一次由next操作获取的元素,使用前必须调用next(),不能单独使用,否则抛出IllegalStateException异常
    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            // 移除lastRet下标处的元素
            ArrayList.this.remove(lastRet);
            // 更新cursor为当前下标,并将lastRet至为-1
            cursor = lastRet;
            lastRet = -1;
            // 更新修改次数
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void forEachRemaining(Consumer<? super E> consumer) {
        Objects.requireNonNull(consumer);
        final int size = ArrayList.this.size;
        int i = cursor;
        if (i >= size) {
            return;
        }
        final Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        }
        while (i != size && modCount == expectedModCount) {
            consumer.accept((E) elementData[i++]);
        }
        // update once at end of iteration to reduce heap write traffic
        cursor = i;
        lastRet = i - 1;
        checkForComodification();
    }

    // 检查修改次数是否与预期相符合,否则抛出异常
    // 快速失败机制
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

面试问题

  1. ArrayList插入删除一定慢么?
    取决于你删除的元素离数组末端有多远,ArrayList拿来作为堆栈来用还是挺合适的,push和pop操作完全不涉及数据移动操作。
  2. ArrayList的遍历和LinkedList遍历性能比较如何?
    论遍历ArrayList要比LinkedList快得多,ArrayList遍历最大的优势在于内存的连续性,CPU的内部缓存结构会缓存连续的内存片段,可以大幅降低读取内存的性能开销。
  3. ArrayList是如何扩容的?
    ArrayList扩容后的大小等于扩容前大小的1.5倍,当ArrayList很大的时候,这样扩容还是挺浪费空间的,甚至会导致内存不足抛出OutOfMemoryError。扩容的时候还需要对数组进行拷贝,这个也挺费时的。所以我们使用的时候要竭力避免扩容,提供一个初始估计容量参数,以免扩容对性能带来较大影响。
  4. ArrayList是线程安全的么?
    当然不是,线程安全版本的数组容器是Vector。Vector的实现很简单,就是把所有的方法统统加上synchronized就完事了。你也可以不使用Vector,用Collections.synchronizedList把一个普通ArrayList包装成一个线程安全版本的数组容器也可以,原理同Vector是一样的,就是给所有的方法套上一层synchronized。
  5. 数组用来做队列合适么?
    队列一般是FIFO的,如果用ArrayList做队列,就需要在数组尾部追加数据,数组头部删除数组,反过来也可以。但是无论如何总会有一个操作会涉及到数组的数据搬迁,这个是比较耗费性能的。
    所以ArrayList固然不适合做队列,但是数组是非常合适的。比如ArrayBlockingQueue内部实现就是一个环形队列,它是一个定长队列,内部是用一个定长数组来实现的。简单点说就是使用两个偏移量来标记数组的读位置和写位置,如果超过长度就折回到数组开头,前提是它们是定长数组。
  6. 多线程操作时,会出现什么问题?
    数据丢失,添加null数据,下标越界,引用异常(非法修改)
    由于 赋值操作elementData[size++] = e,扩容操作ensureCapacityInternal(size + 1),在多线程情况下数据不一致。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值