ArrayList底层为数组结构,add方法:
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index);//这是一个本地native方法 elementData[index] = element; size++; }
set方法:
public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
LinkedList底层为链表结构,set方法:
public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
看一下Node:
private static class Node<E> { E item;//本项元素 Node<E> next;//下一个元素 Node<E> prev;//前一个元素 Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
看一下node(index)方法是如何根据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; } }
下面看一下LinkedList的add方法:
public void add(int index, E element) { checkPositionIndex(index);//检查下标合法 if (index == size) linkLast(element);//在末尾加元素 else linkBefore(element, node(index));//在中间加元素 }
void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null);//构造新的最后Node节点,设置后一个元素为null last = newNode; if (l == null)//数组内没有元素 first = newNode; else//设置前一个元素的后指向 l.next = newNode; size++; modCount++; }
linkLast方法比较简单,看一下linkBefore:
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);//构造新的Node节点,设置前后指向 succ.prev = newNode;//设置后一个元素的前指向 if (pred == null)//设置前一个元素的后指向 first = newNode; else pred.next = newNode; size++; modCount++; }
因此:
ArrayList在随机访问(get,set)方面更高效(直接根据下标就可找到元素,LinkedList需要从最前或者最后进行依次查找)
LinkedList在List的中间插入和移除时更高效(LinkedList最多涉及三个元素的的更改,ArrayList需要对中间插入元素后面的所有元素进行后移一位的操作)
另外: