ArrayList,LinkedList和Vector都继承自List接口。ArrayList和Vector的底层是动态数组,LinkedList的底层是双向链表.
ArrayList和Vector的区别就是ArrayList是线程不安全的,Vector是线程安全的,Vector中的方法都是同步方法(synchronized),所以ArrayList的执行效率要高于Vector,它也是用的最广泛的一种集合。
我们重点比较一下ArrayList和LinkedList的区别,其实ArrayList和LinkedList之间的区别就是数组和双向链表之间的区别。
数组的特点:因为数组分配的是一块连续的内存空间,使用索引来查找元素是非常快速的。但是插入,删除数据性能比较低。
要把邓丽君删掉需要先把从王志文开始的元素挨个往前移,将邓丽君覆盖掉。
再来看一下双向链表的结构:
在该链表中每一个元素除了存储本身的内容之外还存储指向前一个元素的指针和指向后一个元素的指针,下图展示了一个包含三个元素的双向链表,每个链表都有一个头部,头部指向第一个元素,尾部元素也指向头部。
双向链表的特点,查询效率较低,因为查询一个元素需要从头部开始查询,挨个遍历每一个元素直到找到所需元素,插入,删除效率高比如我们删掉一个元素直接把它前一个元素的指针指向它后一个元素就可以了:
我们通过源码来比价一下这两种数据结构集合的特点
1. 添加元素到集合尾部:List接口提供了一个方法可以将元素添加到集合的尾部boolean add(E e),ArrayList和LinkedList都实现了这个方法:
先看ArrayList是如何实现的:
public boolean add(E e) { ensureCapacityInternal(size + 1); //判断当前数组的容量是否够大如果不够大则扩容 elementData[size++] = e;//将元素添加到数组尾部 return true; }
这里的执行效率取决于:ensureCapacityInternal(size+ 1)方法的执行,在该方法中会判断数组容量是否足够,如果不够则进行扩容到原来的1.5倍。在扩容的过程中会生成一个新的数组,将原数组中的元素复制到新数组中。所以在这种情况下如果数组容量足够大ArrayList的效率是非常高的,我们也可以根据实际情况给它一个合适的初始值。
再来看一下LinkedList集合:
public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
我们可以看到每新增一个元素就要创建一个Node对象,进行频繁的赋值操作 “final Node<E> newNode = new Node<>(l, e, null);”对效率有一定的影响。
我们再来看一下在特定的位置插入元素:
List接口中提供的方式是这样的:void add(int index,E element)
在ArrayList中是这样实现的:
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
从代码中我们可以看出,每插入一个元素就要进行大量元素复制操作:“System.arraycopy(elementData, index, elementData, index + 1,size - index);”
从插入点往后的元素依次后移将新元素插入到空出来的位置上。效率非常低下。
而在LinkedList中开销和在集合最后插入元素开销差不多,只需要把它前一个元素的指针指向自己,自己的指针指向下一个元素就可以了。
总结一下:
1. ArrayList和Vector结构一样都是动态数组,区别是ArrayList是线程不安全的,Vector是线程安全的,ArrayList性能好于Vector,ArrayList是应用最多的集合。
2. ArrayList和LinkedList的区别是他们的数据结构不同,ArrayList是动态数组,LinkedList是双向链表,在查询操作较多,在特定位置插入数据和删除数据较少的情况下一般选用ArrayList,在特定位置插入数据,删除数据操作较多,查询较少的情况下一般选用LinkedList,但是在大多数应用中都是对查询效率要求较高,所以ArrayList集合应用更广泛一些。