1. List概括
(1)List是一个接口,它继承Collection接口,代表有序的队列。
(2)ArrayList,LinkedList,Vector都是List的实现类。
ArrayList是一个数组队列,相当于动态数组,是由数组实现的,随机访问效率高,随机插入,增删效率低。
LinkedList是一个双向链表,随机插入,增删效率高,但是随机访问效率低。
Vector和ArrayList一样,都是采用了数组的数据结构,但是ArrayList是非线程安全的,而Vector是线程安全的。
2. List的使用场景
(1)对于需要快速插入,删除元素,应该选择LinkedList;
(2)对于需要快速随机访问元素,应该选择ArrayList;
(3)Vector是线程安全的,效率较低,现在使用较少;
几种遍历实现:
public class CollectionCompare { public static final int COUNT = 1000; private static ArrayList arrayList = new ArrayList(); private static LinkedList linkedList = new LinkedList(); private static Vector vector = new Vector(); public static void main(String[] args) { insertByPosition(arrayList); insertByPosition(linkedList); insertByPosition(vector); getByPosition(arrayList); getByPosition(linkedList); getByPosition(vector); removeByPosition(arrayList); removeByPosition(linkedList); removeByPosition(vector); }
//获取 private static void getByPosition(List list) { long startTime = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { list.get(i); } long endTime = System.currentTimeMillis(); long interval = endTime - startTime; System.out.println(getListName(list) + ":get " + COUNT + " elements use time " + interval + "ms"); }
//插入 public static void insertByPosition(List list){ long startTime = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { list.add(0,i); } long endTime = System.currentTimeMillis(); long interval = endTime - startTime; System.out.println(getListName(list) + ":insert " + COUNT + " elements use time " + interval + "ms"); }
//删除 public static void removeByPosition(List list){ long startTime = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { list.remove(0); } long endTime = System.currentTimeMillis(); long interval = endTime - startTime; System.out.println(getListName(list) + ":remove " + COUNT + " elements use time " + interval + "ms"); } private static String getListName(List list) { if (list instanceof ArrayList){ return "ArrayList"; }else if(list instanceof LinkedList){ return "LinkedList"; }else if(list instanceof Vector){ return "Vector"; }else{ return "List"; } } }
3. LinkedList和ArrayList性能差异分析
LinkedList中指定位置插入元素
//在指定位置插入元素 public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); } //先要找到要插入位置的节点,如果要插入位置小于集合一半大小,则从前开始查找,否则从后开始找 Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } } //新建节点Node,插入元素 void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
给LinkedList指定位置插入元素,调用add(int index, E element)方法,需要先找到插入节点的位置index;而插入位置时:如果index<size/2,则从前往后开始找,否则从后往前开始找,找到index位置后,然后再插入新节点。
ArrayList中指定位置插入元素
public void add(int index, E element) { rangeCheckForAdd(index); modCount++; final int s; Object[] elementData; if ((s = size) == (elementData = this.elementData).length) elementData = grow(); System.arraycopy(elementData, index, elementData, index + 1, s - index); elementData[index] = element; size = s + 1; }
ArrayList中插入元素主要耗时的是调用System.arraycopy(elementData, index, elementData, index + 1, size - index)方法,这是一个native方法,底层是c/c++实现,在插入过程中会移动index位置后的所有元素。
所以使用ArrayList插入元素相较于LinkedList耗时。
随机访问LinkedList元素
//获取指定位置的元素 public E get(int index) { checkElementIndex(index); return node(index).item; } //获取指定位置的节点,和插入元素原理相同 Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
随机访问LinkedList和插入元素的原理相同,也是先找到指定位置的节点,然后再返回元素。
随机访问ArrayList中的元素
public E get(int index) { Objects.checkIndex(index, size); return elementData(index); }
随机访问ArrayList中元素通过调用get()方法,直接返回数组中index位置的元素,而不需要像LinkedList那样查找元素。
所以使用ArrayList随机访问元素相较于LinkedList元素效率较高。