类结构
LinkedList底层采用双向链表结构存储数据,允许重复数据和null值,长度没有限制:
每个节点用内部类Node表示:
1 | java复制代码private static class Node<E> { |
Node节点包含item(存储数据),next(后继节点)和prev(前继节点)。数组内存地址必须连续,而链表就没有这个限制了,Node可以分布于各个内存地址,它们之间的关系通过prev和next维护。
LinkedList类关系图:
可以看到LinkedList类并没有实现RandomAccess接口,额外实现了Deque接口,所以包含一些队列方法。
LinkedList包含如下成员变量:
1 | java复制代码// 元素个数,默认为0 |
方法解析
构造函数
LinkedList()
:
1 | java复制代码public LinkedList() {} |
空参构造函数,默认size为0,每次添加新元素都要创建Node节点。
LinkedList(Collection<? extends E> c)
:
1 | java复制代码public LinkedList(Collection<? extends E> c) { |
该构造函数用于创建LinkedList,并往里添加指定集合元素。
add(int index, E element)
add(int index, E element)
指定下标插入元素:
1 | java复制代码public void add(int index, E element) { |
无非就是设置节点的prev和next关系。可以看到,除了头插和尾插外,在链表别的位置插入新节点,涉及到节点遍历操作,所以我们常说的链表插入速度快,指的是插入节点改变前后节点的引用过程很快。
get(int index)
get(int index)
获取指定下标元素:
1 | java复制代码public E get(int index) { |
通过node函数查找指定index下标Node,然后获取其item属性值,节点查找需要遍历。
set(int index, E element)
set(int index, E element)
设置指定下标节点的item为指定值:
1 | java复制代码public E set(int index, E element) { |
可以看到,set方法也需要通过遍历查找目标节点。
remove(int index)
remove(int index)
删除指定下标节点:
1 | java复制代码public E remove(int index) { |
remove(int index)
通过node方法找到需要删除的节点,然后调用unlink方法改变删除节点的prev和next节点的前继和后继节点。
剩下的方法可以自己阅读源码。
RandomAccess接口
RandomAccess接口是一个空接口,不包含任何方法,只是作为一个标识:
1 | java复制代码package java.util; |
实现该接口的类说明其支持快速随机访问,比如ArrayList实现了该接口,说明ArrayList支持快速随机访问。所谓快速随机访问指的是通过元素的下标即可快速获取元素对象,无需遍历,而LinkedList则没有这个特性,元素获取必须遍历链表。
在Collections类的binarySearch(List<? extends Comparable<? super T>> list, T key)
方法中,可以看到RandomAccess的应用:
1 | java复制代码public static <T> |
当list实现了RandomAccess接口时,调用indexedBinarySearch方法,否则调用iteratorBinarySearch。所以当我们遍历集合时,如果集合实现了RandomAccess接口,优先选择普通for循环,其次foreach;遍历未实现RandomAccess的接口,优先选择iterator遍历。
本文转载自: 掘金