类图结构
LinkedList是List接口和Deque接口的双向链表实现类。它的类层级结构如图所示:
LinkedList继承自AbstractSequentialList,说明LinkedList具有顺序遍历的特性(ArrayList实现了RandomAccess接口具有随机遍历的特性),另外它还实现了Deque接口,说明LinkedList具有双端队列操作的特性。
类文件说明
LinkedList元素类型是泛型,可以存放【所有】类型的元素,包括null。LinkedList的元素以双链表的形式存储,因此在指定位置插入或删除元素需要从头顺序遍历或从尾反向顺序遍历到指定index所在的位置。所以ArrayList随机访问肯定比LinkedList快。那添加和删除操作LinkedList比ArrayList快吗?NO!添加和删除元素综合性能两者差不多!
ArrayList在指定index处添加或删除元素时,主要耗时在要System.arraycopy,它要移动指定index后面所有的元素。
LinkedList在指定index添加或删除元素时,主要耗时在需要从头顺序遍历或从尾反向顺序遍历到指定index所在的位置。
所以:
当指定插入或删除元素的位置越靠前时,ArrayList的性能越差。
当指定插入或删除元素的位置越靠中间时,LinkedList的性能越差。
数据量小时基本没什么区别,不用考虑;数据量大时,如果在中间位置插入或删除的操作增多,此时LinkedList性能并不比ArrayList好。
综上:一般选用ArrayList即可。LinkedList主要用于特殊数据结构栈、队列、双端队列操作时使用。
LinkedList内部元素双链表结构如下:
每个节点都有一个前驱指针和后驱指针,节点数据结构如下:
1 | private static class Node<E> { |
LinkedList数据结构如下:只有三个属性:size、first、last。注释上有说:
- first为null时last也必为null表示是空链表
- 第二点:first.prev == null && first.item != null验证了不对,item是可以为null的
- 第三点同上:last.item也是可以为null的
1 | transient int size = 0; |
linkFirst
linkFirst在头部添加元素,需要进行指针移动操作如下:
1 | /** |
操作前后图示:
linkLast
linkLast在尾部添加元素,需要进行指针移动操作如下:
1 | /** |
操作前后图示:
linkeBefore
linkBefore在指定node前添加元素,需要进行指针移动操作如下:
1 | /** |
操作前后图示:
get
LinkedList实现了List接口,所以支持按index获取元素的操作
1 | public E get(int index) { |