1、简述
LinkList的底层其实就是一个双向链表,所谓的链表就是一个LinkList内部静态静态类(Node),对LinkList的所有操作本质上就是通过对LinkList中新建的Node对象
进行关联引用
2、实现
a、构造方法:
LinkList一共提供了两种构造方法:
/*** Constructs an empty list.*/
publicLinkedList() {
}/*** Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
*@paramc the collection whose elements are to be placed into this list
*@throwsNullPointerException if the specified collection is null*/
public LinkedList(Collection extends E>c) {this();
addAll(c);
}
b、定义内部私有属性
transient int size = 0;/*** Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)*/
transient Nodefirst;/*** Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)*/
transient Node last;
LinkList的内部属性只有三个,一个是LinkList的长度,另外两个分别是第一个节点和最后一个节点,每次对LinkList进行更新操作之后,第一个节点和最后一个节点的值都会进行相应的变化。
3、LinkList操作
增加操作:
add(E e):
/*** Appends the specified element to the end of this list.
*
*
This method is equivalent to {@link#addLast}.
*
*@parame element to be appended to this list
*@return{@codetrue} (as specified by {@linkCollection#add})*/
public booleanadd(E e) {
linkLast(e);return true;
}/*** Links e as last element.*/
voidlinkLast(E e) {final Node l =last;final Node newNode = new Node<>(l, e, null);
last=newNode;if (l == null)
first=newNode;elsel.next=newNode;
size++;
modCount++;
}
调用add(E e)操作LinkList的时候先new一个Node对象,并设置该节点的上一个元素为之前的最后一个节点,然后再将之前最后一个节点的next属性指向新建的节点
add(int index, E element):
/*** Inserts the specified element at the specified position in this list.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
*@paramindex index at which the specified element is to be inserted
*@paramelement element to be inserted
*@throwsIndexOutOfBoundsException {@inheritDoc}*/
public void add(intindex, E element) {
checkPositionIndex(index);if (index ==size)
linkLast(element);elselinkBefore(element, node(index));
}/*** Inserts element e before non-null Node succ.*/
void linkBefore(E e, Nodesucc) {//assert succ != null;
final Node pred =succ.prev;final Node newNode = new Node<>(pred, e, succ);
succ.prev=newNode;if (pred == null)
first=newNode;elsepred.next=newNode;
size++;
modCount++;
}
调用add(int index, E element)操作的时候和add(E element)方法是一样的,就是通过改变index位置节点的中的next和prev属性的值,再将新创建的节点的next指向原来index位置的节点
LinkList的删除更新操作本质其实就是通过对内部节点的next和prev属行引用的值进行改变,所以在这里就不再对那些操作一一叙述了
总结:
之前因为刚看完ArrayList,ArrayList内部是通过数组来对内部数据的保存,所以开始一直纠结这LinkList的数据是保存在哪里的,其实LinkList的数据是直接保存在jvm中的,因为往LinkList中增加数据的时候,其实就是new了一个ArrayList的静态内部类的对象,只不过LinkList的first和last属性指向了这些对象的引用,所以这些对象是一直不会被gc回收的,当LinkList删除一个元素的时候,只不过是将其他的节点对那个节点的引用给删除,然后被删除的那个对象没了引用就会被gc回收。这样的实现方式导致了LinkList里面的元素的jvm中的分布是杂乱的,所以当你根据下标去获取LinkList中的元素是只能通过一个个的去遍历,这样也就导致了它的读取效率低