跪拜 Guibai
← Back to the summary

A Swing GUI That Shows Exactly How LinkedList Rewires Nodes on add() and remove()

[Java] Showing the Internal Changes of LinkedList When Adding and Removing Elements

Background

I previously wrote [Java] Showing the internal changes of ArrayList when adding elements, which displayed ArrayList's internal changes when adding elements. Later I thought LinkedList's internal changes during add and remove operations could also be presented in GUI form. I used trae to complete this Java code.

Notes

The full code uses the record syntax, so compilation and running require JDK 16+ (including 16).

Main text

How to run

For the flow of the text, the full code section provides the complete code. Save the complete code as LinkedListBehaviorDemo.java. Use the following command to compile it:

javac LinkedListBehaviorDemo.java

After compilation, the following class files are produced:

Run the main method in LinkedListBehaviorDemo with the following command. (Reflection access to private fields in java.util is restricted by the JDK 9+ module system, so the --add-opens option is required):

java --add-opens=java.base/java.util=ALL-UNNAMED LinkedListBehaviorDemo

Run result examples

Initial state

image.png

Constructor

Clicking the new LinkedList<String>() button calls LinkedList's default constructor and produces an instance:

image.png

Adding elements

Click one of the following buttons to add an element to the LinkedList:

image.png

After clicking, the corresponding LinkedList method is called:

image.png

Example after adding elements:

image.png

Removing elements

Click one of the following buttons to remove an element from the LinkedList:

image.png

After clicking, the corresponding LinkedList method is called:

image.png

Show logical chain button

This button shows each node's logical order, including both next references and prev references.

image.png

Show heap scatter button

This button shows the distribution of nodes (it does not show the real addresses of nodes). The next references of nodes can be displayed:

image.png

The prev references of nodes can also be displayed:

image.png

Reset button

This button restarts the demo.

Current state

This control shows the size, first, and last fields of the LinkedList:

image.png

The size/first/last values come from LinkedList:

image.png

Observation points

Background: LinkedList's internal structure

LinkedList internally maintains only four fields:

The following code verifies this (save it as LinkedListFieldsCliDemo.java):

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.LinkedList;

/**
 * Lists the fields declared by java.util.LinkedList via reflection.
 * <p>
 * getDeclaredFields() only reads metadata, not field values, so no
 * setAccessible and no --add-opens are needed:
 * <pre>
 * javac LinkedListFieldsCliDemo.java
 * java  LinkedListFieldsCliDemo
 * </pre>
 */
public class LinkedListFieldsCliDemo {

    public static void main(String[] args) {
        System.out.println("== fields declared by java.util.LinkedList ==");
        for (Field f : LinkedList.class.getDeclaredFields()) {
            System.out.printf("    %-24s %-28s %s%n",
                    Modifier.toString(f.getModifiers()),
                    f.getType().getName(),
                    f.getName());
        }
    }

}

image.png

Each node is an independent object:

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

Nodes are not stored in a contiguous array: each node is an independent object on the heap, and the order of the list exists only in the next/prev references. The GUI provides two switchable views:

Facts observable through the demo

Full code

// The complete LinkedListBehaviorDemo.java source from the original article
// (Swing UI, ChainView, reflection access, and main method) is included here.

LinkedList class diagram

The following class diagram is based on JDK 21 and ignores generic information:

image.png

LinkedList reuses skeleton implementations through AbstractSequentialList -> AbstractList -> AbstractCollection, and implements the List interface and the Deque interface, so it can be used both as a list and as a double-ended queue.

How to draw the class diagram for java.util.LinkedList?

I used the code from [Java] How to automatically generate a simple PlantUML class diagram. The key commands are:

javac ClassDiagramGenerator.java
java ClassDiagramGenerator 'java.util.LinkedList'

The output of the second command is (from JDK 21):

@startuml

interface java.util.List
interface java.lang.Cloneable
interface java.lang.Iterable
interface java.util.Queue
interface java.util.SequencedCollection
interface java.io.Serializable
interface java.util.Deque
interface java.util.Collection
abstract java.util.AbstractCollection
abstract java.util.AbstractSequentialList
abstract java.util.AbstractList
class java.util.LinkedList
java.lang.Iterable <|-- java.util.Collection
java.util.Collection <|.. java.util.AbstractCollection
java.util.Collection <|-- java.util.SequencedCollection
java.util.SequencedCollection <|-- java.util.List
java.util.AbstractCollection <|-- java.util.AbstractList
java.util.List <|.. java.util.AbstractList
java.util.AbstractList <|-- java.util.AbstractSequentialList
java.util.Collection <|-- java.util.Queue
java.util.Queue <|-- java.util.Deque
java.util.SequencedCollection <|-- java.util.Deque
java.util.AbstractSequentialList <|-- java.util.LinkedList
java.util.List <|.. java.util.LinkedList
java.util.Deque <|.. java.util.LinkedList
java.lang.Cloneable <|.. java.util.LinkedList
java.io.Serializable <|.. java.util.LinkedList

@enduml

With the PlantUML plugin in IntelliJ IDEA (Community Edition), the puml above can be converted into a class diagram.

References