继承关系
java.util
类 LinkedList
java.lang.Object
继承者 java.util.AbstractCollection
继承者 java.util.AbstractList
继承者 java.util.AbstractSequentialList
继承者 java.util.LinkedList
所有已实现的接口:
Serializable, Cloneable, Iterable, Collection, Deque, List, Queue
源码分析
LinkedList实际上是通过双向链表去实现的。
获取元素方法get()方法直接调用node(int index)方法。
(实际原理非常简单,它就是通过一个计数索引值来实现的。例如,当我们调用get(int location)时,首先会比较“location”和“双向链表长度的1/2”;若前者大,则从链表头开始往后查找,直到location位置;否则,从链表末尾开始先前查找,直到location位置。)
因此,访问效率上,根据索引的随机访问很慢,顺序访问效率高。当然,本身就是适用于链表场景。
* 所以,千万不要用链表来做随机访问元素的事,除非特例,否则一定是你用错数据结构了*
/**
* Returns the (non-null) Node at the specified element index.
*/
Node node(int index){
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next; //不断替换链表的下一个节点引用,即链表挨个查找下去,直到index位置
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;//同理
return x;
}
}
遍历
1、Iterator
2、fori
慎用,效率低,玩死你的cpu
3、foreach
4、从API获得元素节点对象,沿链表挨个循环调用访问
如:
while(list.pollFirst() != null){
;
}
多线程访问
如果多个线程同时访问一个链接列表,有两种方式:
1、自己实现同步操作,保证读写列表的操作是同步的
2、使用 Collections.synchronizedList 方法来“包装”该列表
List list = Collections.synchronizedList(new LinkedList(…));
所谓包装,很贴切,就是用修饰模式,加了个壳,所有list方法变成同步操作
static List synchronizedList(List list, Object mutex) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list, mutex) :
new SynchronizedList<>(list, mutex));
}
static class SynchronizedList
extends SynchronizedCollection
implements List {
final List list;
SynchronizedList(List list) {
super(list);
this.list = list;
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
… …
}
特点小结
(01) LinkedList 实际上是通过双向链表去实现的。
(02) 容量上,增长受限于内存,没有显性限制
(03) LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。
(04) LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
(05) 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。
(06) LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下表的方法等价:
队列方法 等效方法
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()
(07) LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:
栈方法 等效方法
push(e) addFirst(e)
pop() removeFirst()
peek() peekFirst()