讨论集合关注的问题:
- 底层数据结构
- 增删改查方式
- 初始容量,扩容方式,扩容时机
- 线程安全与否
- 是否允许空,是否允许重复,是否有序
我们都知道Collection接口派生出三大类的子接口List,Set和Queue。今天继续看List这个系列下的LinkedList,关于ArrayList和Vector前篇已经讲过。
LinkedList和ArrayList都属于List集合的“范畴”,很大程度上与LinkedList的使用方式类似,区别主要在底层的实现上。顾名思义,LinkedList其底层采用了链表的方式来维护集合中的数据。而Queue队列,是3大类中比较特殊的一类,其子类较少,一般和其他的集合中进行关系的维护。例如LinkedList中就使用了一个双向队列。
LinkedList
LinkedList是一个List接口的“范畴”,我这里说的并不准确,但是一般在开发中采用的“接口+实现类”的方式中,就经常使用List接口来指向其被实现的类,这样大部分的增删改查的操作方法都可以使用自List接口的调用。
LinkedList继承自AbstractSequentialList(AbstractList的子类)类,实现了List, Deque, Cloneable, Serializable,说明LinkedList可以进行克隆和序列化操作,其在序列化时,会序列化所有的非空数据。
LinkedList使用一个头结点first,一个尾节点last,和一个内部类Node来维护集合中的数据,Node是一个具有前后指针的节点结构,来完成链表的双向操作。
LinkedList非线性安全。
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;
}
}
添加新的元素时,默认添加到链表的末尾。同样可以指定添加的位置,都需要通过first指针一直遍历下去,知道找到合适的位置。添加元素主要是linklast和linkbefore两个方法:
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