Source code analysis of the collections list of Java Collection Series
I. Introduction to tranquility list
A sort list is an ordered sequence that allows efficient insert and remove operations at any location. It is implemented based on a two-way linked list.
Ps: Here is a question about whether or not the data structure of the sorted list is a circular two-way linked list. Many articles on the Internet have said it is a loop, in some articles, I read the source code and think it should not be a loop?
For example, the Code of deleting a node at the end of the list:
private E unlinkLast(Node
l) { final E element = l.item; final Node
prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; }
After the last node l is deleted, the next of the node prev prior to l is set to null without pointing to the head node. I don't know if it is because of the code version (my source code is obtained in the downloaded jdk1.8.0 _ 45 file). If you see the reason, I hope you can help me solve it!
The basic structure of the node is defined in the source code:
Private static class Node
{E item; // indicates the Node value contained by the Node.
Next; // represents the next Node of the current Node
Prev; // indicates the previous Node of the current Node (Node
Prev, E element, Node
Next) {this. item = element; this. next = next; this. prev = prev ;}}
The category list class diagram is as follows:
A two-way linked list inherited from AbstractSequentialList. It can also be operated as a stack, queue, or double-end queue.
The listlist interface can be used to operate queues.
Consumer List implements the Deque interface, which can be used as a dual-end queue.
Javaslist implements the Cloneable interface, which overwrites the function clone () and can be cloned.
The serialize List implements the java. io. Serializable interface, which means that the serialize List supports serialization and can be transmitted through serialization.
The synchronized list is not synchronous.
Ii. Source Code Analysis of the shortlist
Public class upload list
Extends AbstractSequentialList
Implements List
, Deque
, Cloneable, java. io. serializable {// when the Serilizable interface is implemented, the transient keyword is added before the attribute that does not need to be serialized. When the object is serialized, this attribute is not serialized to the specified destination. Transient int size = 0; // point to the first Node transient Node
First; // point to the last Node transient Node
Last; // construct an empty list public writable list () {}// construct a list public writable list (Collection
C) {this (); addAll (c) ;}// use the Node with the Node value e as the first Node private void linkFirst (E e) {final Node
F = first; // construct a Node final Node whose prev value is null, next is f, and Node value is e.
NewNode = new Node <> (null, e, f); // use newNode as the first Node first = newNode; // if there is no node after newNode, use newNode as the last node. if (f = null) last = newNode; // otherwise, newNode is assigned to its prev else f. prev = newNode; // The list Length plus a size ++; modCount ++;} // use the Node with the Node value e as the last Node void linkLast (E e) {final Node
L = last; // construct a Node final Node whose prev value is l, next is null, and Node value is e
NewNode = new Node <> (l, e, null); last = newNode; if (l = null) first = newNode; else l. next = newNode; size ++; modCount ++;} // insert Node e void linkBefore (E e, Node
Succ) {final Node
Pred = succ. prev; // use the Node before succ and succ as its prev and next final Node
NewNode = new Node <> (pred, e, succ); // use newNode as the prev succ of succ. prev = newNode; // if the original succ is the first node, set newNode as the first node if (pred = null) first = newNode; else pred. next = newNode; size ++; modCount ++;} // release non-empty first Node f private E unlinkFirst (Node
F) {final E element = f. item; final Node
Next = f. next; f. item = null; f. next = null; // help GC // set the node after the first node to the first node first = next; if (next = null) last = null; else next. prev = null; size --; modCount ++; return element;} // release non-empty end Node l private E unlinkLast (Node
L) {final E element = l. item; final Node
Prev = l. prev; l. item = null; l. prev = null; // help GC last = prev; if (prev = null) first = null; else prev. next = null; size --; modCount ++; return element;} // Delete non-empty Node x E unlink (Node
X) {final E element = x. item; final Node
Next = x. next; // The final Node after x
Prev = x. prev; // if (prev = null) {first = next;} else {prev. next = next; x. prev = null;} if (next = null) {last = prev;} else {next. prev = prev; x. next = null;} x. item = null; size --; modCount ++; return element;} // return the value of the first Node in the list. public E getFirst () {final Node
F = first; if (f = null) throw new NoSuchElementException (); return f. item;} // return the value of the final Node element at the end of the list public E getLast () {final Node
L = last; if (l = null) throw new NoSuchElementException (); return l. item;} // remove the first public E removeFirst () {final Node
F = first; if (f = null) throw new NoSuchElementException (); return unlinkFirst (f) ;}// Delete the End Node public E removeLast () {final Node
L = last; if (l = null) throw new NoSuchElementException (); return unlinkLast (l) ;}// insert node e public void addFirst (E e) in the first part of the list) {linkFirst (e);} // Insert the node e public void addLast (E e) {linkLast (e);} at the end of the list );} // determine whether the list contains the element o public boolean contains (Object o) {return indexOf (o )! =-1;} // return list Length size public int size () {return size;} // Insert the public boolean add (E e) element at the end of the list) {linkLast (e); return true;} // Delete the public boolean remove (Object o) {if (o = null) {for (Node
X = first; x! = Null; x = x. next) {if (x. item = null) {unlink (x); return true ;}} else {for (Node
X = first; x! = Null; x = x. next) {if (o. equals (x. item) {unlink (x); return true ;}} return false ;}// add all the elements in set c to the end of the list public boolean addAll (Collection
C) {return addAll (size, c);} // inserts the elements in set c into the public boolean addAll (int index, Collection
C) {// determine the validity of the insert position checkPositionIndex (index); Object [] a = c. toArray (); int numNew =. length; if (numNew = 0) return false; Node
Pred, succ; if (index = size) {// description Insert the set element succ = null at the end of the list; pred = last;} else {// otherwise, locate the node succ = node (index); pred = succ where the index is located. prev;} for (Object o: a) {@ SuppressWarnings (unchecked) E e = (E) o; Node
NewNode = new Node <> (pred, e, null); if (pred = null) first = newNode; else pred. next = newNode; pred = newNode;} if (succ = null) {last = pred;} else {pred. next = succ; succ. prev = pred;} size + = numNew; modCount ++; return true ;}// delete all nodes in the list public void clear () {for (Node
X = first; x! = Null;) {Node
Next = x. next; x. item = null; x. next = null; x. prev = null; x = next;} first = last = null; size = 0; modCount ++ ;} // obtain the value of the element public E get (int index) {checkElementIndex (index); return node (index) at the specified index position ). item;} // Replace the element value of the Node at the specified index position with public E set (int index, E element) {checkElementIndex (index); Node
X = node (index); E oldVal = x. item; x. item = element; return oldVal;} // Insert the element e public void add (int index, E element) {checkPositionIndex (index) before the specified index location ); if (index = size) linkLast (element); else linkBefore (element, node (index);} // Delete the public E remove (int index) element at the specified position) {checkElementIndex (index); return unlink (node (index);} // determines whether the elements at the specified index position have private boolean isElementIndex (int index) {return I Ndex> = 0 & index <size;} private boolean isPositionIndex (int index) {return index> = 0 & index <= size ;} // construct IndexOutOfBoundsException details private String outOfBoundsMsg (int index) {return Index: + index +, Size: + size;} private void checkElementIndex (int index) {if (! IsElementIndex (index) throw new IndexOutOfBoundsException (outOfBoundsMsg (index);} private void checkPositionIndex (int index) {if (! IsPositionIndex (index) throw new IndexOutOfBoundsException (outOfBoundsMsg (index);} // return the Node at the specified index location
Node (int index) {// here is a tip, when the index
> 1) {Node
X = first; for (int I = 0; I <index; I ++) x = x. next; return x;} else {Node
X = last; for (int I = size-1; I> index; I --) x = x. prev; return x ;}/// returns the position where o appears for the first time in the list. If it does not exist,-1 public int indexOf (Object o) {int index = 0 is returned; if (o = null) {for (Node
X = first; x! = Null; x = x. next) {if (x. item = null) return index; index ++ ;}} else {for (Node
X = first; x! = Null; x = x. next) {if (o. equals (x. item) return index; index ++;} return-1 ;}// reverse search, returns the position where the first occurrence of o, -1 public int lastIndexOf (Object o) {int index = size; if (o = null) {for (Node
X = last; x! = Null; x = x. prev) {index --; if (x. item = null) return index ;}} else {for (Node
X = last; x! = Null; x = x. prev) {index --; if (o. equals (x. item) return index ;}} return-1;} // obtain the element value of the first Node in the list public E peek () {final Node
F = first; return (f = null )? Null: f. item;} // obtain the value of the first node in the list. If it is null, an exception public E element () {return getFirst () ;}// retrieves the first node, if it is null, null is returned. If it is not null, its element value is returned and the first Node public E poll () {final Node is deleted.
F = first; return (f = null )? Null: unlinkFirst (f);} // retrieves the first node. If it is null, an exception is thrown. If it is not null, its element value is returned and the first node public E remove () is deleted () {return removeFirst ();} // add the node e public boolean offer (E e) {return add (e);} at the end of the list );} // insert node e public boolean offerFirst (E e) {addFirst (e); return true;} // insert node e public boolean offerLast (E) at the end of the list) {addLast (e); return true;} public E peekFirst () {final Node
F = first; return (f = null )? Null: f. item;} // obtain the value of the element at the end of the list Node public E peekLast () {final Node
L = last; return (l = null )? Null: l. item;} public E pollFirst () {final Node
F = first; return (f = null )? Null: unlinkFirst (f);} public E pollLast () {final Node
L = last; return (l = null )? Null: unlinkLast (l);} // public void push (E e) {addFirst (e);} // public E pop () {return removeFirst ();} // Delete the public boolean removeFirstOccurrence (Object o) {return remove (o);} // reverse search, delete the public boolean removeLastOccurrence (Object o) {if (o = null) {for (Node
X = last; x! = Null; x = x. prev) {if (x. item = null) {unlink (x); return true ;}} else {for (Node
X = last; x! = Null; x = x. prev) {if (o. equals (x. item) {unlink (x); return true ;}} return false ;}
Iii. Several notes about the vertex list 1. Pay attention to the Node in the source code Node (int index) method:
Node
node(int index) { if (index < (size >> 1)) { Node
x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node
x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
This method returns the node at the specified position in the two-way linked list, and there is no subscript index in the linked list. to specify the element at the position, we need to traverse the linked list. from the implementation of the source code, we can see an acceleration action. In the source code, compare the index with half of the size. If the index Size/2, just traverse from the position size to the position index. This reduces unnecessary traversal.
2. Differences between the rule list and ArrayList:
The role list and ArrayList have their own advantages and disadvantages in terms of performance and have their respective advantages and disadvantages. They are summarized as follows:
- ArrayList implements a dynamic array-based data structure. The ArrayList is based on the linked list data structure.
- The random list does not support efficient random element access.
- The space waste of ArrayList is mainly reflected in the reserved capacity space at the end of the list. The space consumption of the list is reflected in that each of its elements consumes a considerable amount of space, in terms of storage density, the ArrayList is better than the sort list.
In short, when the operation is to add data after a column of data rather than in the front or middle, and needs to randomly access the elements in it, the use of ArrayList will provide better performance, when you add or delete data in front or middle of a column of data and access the elements in the column in sequence, you should use the sort list.
3. The allowed element in the rule list is null.The source code is as follows:
public int indexOf(Object o) { int index = 0; if (o == null) { for (Node
x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { for (Node
x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; }
4. Basic usage of consumer list:We recommend that you describe the basic usage of the shortlist blog.