- 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;
}
}
链表的这种托盘的结构决定了它的的特点:
- 数据的写入很快,但是数据的读取很慢。
- 数据没有扩容的概念。
在链表中有两个托盘:firstNode和lastNode。
transient Node<E> first;
transient Node<E> last;
在第一次添加元素时,新的元素既是firstNode也是lastNode,这点可以在源码中体现。
- 链表中添加(add)方法解析
transient int size = 0;
public void add(int index, E element) {
checkPositionIndex(index);
//checkPositionIndex方法是用来检测index是否在[0,size)中,在返回index,否则抛出
//IndexOutOfBoundsException异常。
if (index == size)
linkLast(element); //添加第一个元素
else
linkBefore(element, node(index)); //添加第N个元素。
}
在add方法中判断是不是第一次添加,size在这里的默认值为0,当第一次添加是index为0,执行linkLast方法。
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
/* 这里的last变量是上文中的托盘 Node<E> last;
* l, e, null 变量的意思是上家,数据元素,下家,这里下家为null.
* 当l == null 时,设置first = newNode;这句话的意思就是
* 【在第一次添加是】新元素既是第一个也是最后一个。
*/
在这里体现了第一个添加的元素既是FirstNode也是LastNode这句话。
而下面这句话 l.next = newNode 体现了链表每个托盘是双向关联的。
当我们添加的数据不是第一个是,就会执行linkBefore方法,但是在分析linkBefore方法之前,我们先来分析一下 Node<E> node(int index)
这个方法:
Node<E> node(int index) {
if (index < (size >> 1)) { //判断index在前半段还是在后半段。
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
这个方法是链表中的查询方法,index在前半段时取出第一个托盘 Node<E> x = first ,往后查 x = x.next
当index在后半段时取出最后一个托盘 Node<E> x = last ,往前查 x = x.prev 。
当找到要插入的位置时,返回所在的托盘, linkBefore(E e, Node<E> succ)方法承接这个托盘,将新的数据插入到该节点之前。
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
/* 首先获取succ的上家记做pred,将pred当做上家传入新创建的托盘newNode中,将succ当做下家传入
* newNode 中,最后形成 new Node<>(pred, e, succ)。
* 如果pred不存在,那就把NowNode设置为firstNode。否则,将
* pred的下家设置为newNode。
*/
以上总结是个人观点,如有存在错误请指正。