LinkedList的底层数据结构是双向链表,每一个元素都有自己的头结点和尾结点和元素值,会记录上一个结点的地址和下一个结点的地址和当前结点的值,下面是部分源码
public LinkedList extends AbstractSequentialList implements List{
//元素个数
transient int size = 0;
//第一个节点
transient Node<E> first;
//最后一个节点
transient Node<E> last;
public LinkedList() {
}
//添加元素时,调用linkLast(e);
public boolean add(E e) {
linkLast(e);
return true;
}
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++;
}
//节点类
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;
}
}
}
当我们刚创建一个LinkedList后,开始向里面添加元素,添加第一个元素时,调用linkLast(e);比如我们第一次添加的元素是“中国”,此时,源码中的l就是null,因为last并没有初始化嘛,没有赋值,而新建的结点newNode就是(null,“中国”,null),然后再讲这个新建的结点地址,比如0x001赋值给last,再进入判断,此时,l是null,name久将新建结点的地址0x001赋值给first,元素个数自加,此时为1,操作数自加,这就是第一个元素新增后的情况;
新增第一个元素的情况:size = 1;first = 0x001;last = 0x001;第一个元素(null,“中国”,null)
然后我们添加第二个元素(我),将last(0x001)赋值给l,再创建一个新结点(0x001,“我”,null),此时的新结点地址是0x002,将这个结点地址赋值给last,再判断当前的l是否为空,不为空,就将新结点的地址赋值给l的尾结点,也就是将第二个结点的地址赋值给第一个结点的尾结点,此时,链表长度为2,操作数为2,first = 0x001,last = 0x002,第一个元素(null,“中国”,0x002),第二个结点(0x001,“我”,null),再次新增元素以此类推