Source Code Analysis-LinkedList

Keywords: Java Programming

Preface

Today we will analyze a List collection class similar to it, LinkedList. However, the underlying implementation of LinkedList is linked list, and their internal implementation is quite different.

(If you want to learn programming by yourself, please search Circle T Community More industry-related information and more industry-related free video tutorials. It's totally free!

1. Overview

Interclass diagrams:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

You can see that LinkedList does not implement the Random Access interface compared to ArrayList, so we can know that it does not support random access. Next, let's look at the implementation of LinkedList

Each linked list stores first and last pointers to the head and tail nodes, respectively:

//Number of total nodes
transient int size = 0;
 //Header node
transient Node<E> first;
//Tail node
transient Node<E> last;

It can be found that LinkedList is based on two-way linked list and uses Node to store linked list node information.

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;
    }
}

Below is the structure of LinkedList:

2. Add

Add new elements

public void add(E e) {
    checkForComodification();
    lastReturned = null;
    if (next == null)
        linkLast(e);
    else
        linkBefore(e, next);
    nextIndex++;
    expectedModCount++;
}

Add to the tail or insert to the specified location

//Tail-insert to the tail node and set the new node as the tail node
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++;
}

//Insert a new node in front of the specified node
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++;
}

3. Modification

public E set(int index, E element) {
    // Check whether index is legal
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

4. Delete

public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

5. fail-fast mechanism

It is worth noting that LinkedList also has fail-fast mechanism when using iterator. Structural operation of LinkedList while iterating triggers Concurrent ModificationException exception. The specific source code is as follows:

public void add(E e) {
    checkForComodification();
    lastReturned = null;
    if (next == null)
        linkLast(e);
    else
        linkBefore(e, next);
    nextIndex++;
    expectedModCount++;
}

public void set(E e) {
    if (lastReturned == null)
        throw new IllegalStateException();
    checkForComodification();
    lastReturned.item = e;
}

public void remove() {
    checkForComodification();
    if (lastReturned == null)
        throw new IllegalStateException();

    Node<E> lastNext = lastReturned.next;
    unlink(lastReturned);
    if (next == lastReturned)
        next = lastNext;
    else
        nextIndex--;
    lastReturned = null;
    expectedModCount++;
}

// fail-fast mechanism
final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

6. Comparison with Array List

  • ArrayList is based on dynamic array and LinkedList is based on bidirectional linked list.
  • They are all threadless collections;
  • ArrayList supports random access, LinkedList does not;
  • LinkedList adds deleted elements anywhere faster than ArrayList.

7. Summary

Here is my fourth article in the Java Collection Class Source Analysis Series, from HashMap, Concurrent HashMap to ArrayList. In fact, the source analysis of these collections classes, I roughly divided into several steps to explain the analysis:

  1. Class Inheritance and Implementation Relations
  2. Internal data structure
  3. Some Important Methods of Addition, Deletion and Amendment
  4. Advantages and disadvantages of this container, security in multi-threaded environment, etc.
  5. Comparisons with similar containers, applicable scenarios, etc.

To sum up, there are still some other containers I haven't analyzed, but as long as we read the source code and think about the analysis according to the above idea, we can have a deeper understanding of the container, rather than just stay at the level of knowing how to use it.

Posted by t_machine on Sun, 28 Jul 2019 20:12:52 -0700