Java集合框架(2) - LinkedList
Java的集合框架其实是常用数据结构的实现,上篇博客我们讲了ArrayList
这种基于数组形式实现的列表,那么这篇博客我们主要讲解基于双向链表实现的列表:LinkedList
。那么这里说一下常见的面试题:Java的ArrayList
和LinkedList
有什么区别?这个问题其实问的其实是数据结构的基础。数组支持随机访问,但是它在列表中间添加和删除元素困难;链表虽然不支持随机访问,但是它在列表中间添加和删除元素简单。
继承与实现体系
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
}
AbstractSequentialList
类:这个类继承了AbstractList
,这说明LinkedList
也是fail-fast
的Deque
接口:这意味着LinkedList
是一个列表,也是一个双端队列Cloneable
接口:它是一个空接口,标识这LinkedList
支持clone
方法Serializable
接口:它也是一个空接口,意味着LinkedList
支持序列化
LinkedList的基石—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
被设计成为静态内部类,它是双向链表的节点,可以看到它有一个前驱prev
,一个后继next
和它本身的数据域item
。这个相信有点数据结构基础的都能看得懂。
LinkedList的常量
private static final long serialVersionUID = 876323262645176354L;
LinkedList的常量没有ArrayList那么多,仅仅只有一个序列号。
LinkedList的变量
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
size
:列表中实际存储元素的个数first
:指向列表的第一个元素的变量last
:指向列表的最后一个元素的变量
LinkedList的构造方法
-
无参构造:这个可以看到什么都没干
public LinkedList() {}
-
有参构造:这个就是将集合c中的元素全部添加到
LinkedList
的实例中去public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
LinkedList的增删改查
-
添加一个元素
public boolean add(E e) { linkLast(e); return true; }
这里我们可以看到调用了一个私有方法
linkLast
。见名知意:向链表的尾部添加元素,也就是我们常说的尾插法。 -
删除一个元素
public E remove(int index) { checkElementIndex(index); return unlink(node(index)); }
可以看到首先判断
index
是否越界,越界的话则直接抛出异常;否则,就是我们所熟知的双向链表删除节点的操作:将前驱节点的next
域置为删除节点的next
域。我们不需要手动free
当前节点的空间,GC会帮我们处理。 -
更新一个节点
public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
依旧是先判断
index
是否越界,越界的化直接抛出异常;否则,找到更新的位置的节点,然后更新为给定的新值element
-
查询一个节点
public E get(int index) { checkElementIndex(index); return node(index).item; }
获取指定位置的节点并返回该节点的值。我们可以看到都是数据结构的基本操作,至于双端队列
Deque
的方法实现起来也是一个思路。