LinkedList与ArrayList的addAll方法比较

这次来从源码角度分析一下LinkedList与ArrayList的addAll方法

之前有研究过LinkedList和ArrayList的remove()方法源码,发现二者分别是基于双向链表和一个数组进行实现的ADT,在后面的开发中,我也就天真的认为LinkedList是直接让list的后继元等于要加的list的第一个元素的引用就完事了,通过对源码的分析,事实并非如此。

First of all, 注意两种集合类的addAll方法的参数都是Collection接口而非具体的实现类

ArrayList

public boolean addAll(Collection 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;
}

对于ArrayList来讲,先通过ensureCapacityInternal()方法提高elementData数组的长度,然后通过native方法System.arraycopy()将新的list拼到原数组尾部并放到elementData中,猜测底层上应该也是一个一个遍历存放的,但是由于是native方法,效率应该是比较高的

LinkedList

public boolean addAll(Collection c) {
        return addAll(size, c);
}
....
public boolean addAll(int index, Collection c) {
    checkPositionIndex(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0)
        return false;

    Node pred, succ;
    if (index == size) {
        succ = null;
        pred = last;
    } else {
        succ = node(index);
        pred = succ.prev;
    }

    for (Object o : a) {
        @SuppressWarnings("unchecked") E e = (E) o;
        Node newNode = new Node<>(pred, e, null);
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }

    if (succ == null) {
        last = pred;
    } else {
        pred.next = succ;
        succ.prev = pred;
    }

    size += numNew;
    modCount++;
    return true;
}

LinkedList的addAll(Collection)方法本质上是调用了addAll(int, Collection)方法,可以看到,该方法中首先将要添加的list转化为了Object[]:

Object[] a = c.toArray();

之后通过增强for遍历这个数组挨个维护前驱元与后继元

for (Object o : a) {
        @SuppressWarnings("unchecked") E e = (E) o;
        Node newNode = new Node<>(pred, e, null);
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }

由于转化为数组和对前驱元与后继元的挨个维护,效率上应该是不如ArrayList的addAll的

为什么LinkedList不直接将list的后继元指向要加的list的第一个元素呢?

这个问题笔者也困扰,查阅了相关的资料,简单的总结了下:

  1. 开头提到过,addAll方法的参数都是Collection,也就是说并没有指定具体是哪一个实现类,因此不能这样操作。至于为什么不按照类型分别处理的,这个可能是java的作者认为性能收益不是很高或是其他原因,暂不明
  2. 第二点为猜测,一般数组的遍历速度比较快,转化为数组来遍历,应该是比通过迭代器遍历Collection要来的快和方便的。

如果您有确定的答案,很希望您能联系我
我的博客

你可能感兴趣的:(java源码)