How LinkedList works
LinkedList internals, doubly linked nodes, List and Deque APIs, iterator edits, reversal techniques, cache and memory costs.
On this page
🔗 What is a Java LinkedList?
A LinkedList is a List whose elements live in separate node objects, and each node points to the previous and next node. Think of it like a train: every carriage knows the carriage in front and behind it, while the railway office keeps pointers to the first and last carriage. If you insert a new song between two playlist entries, the list changes a few arrows instead of shifting a whole array.
For this lesson, we'll focus on how Java 21's java.util.LinkedList is built, why it implements both List and Deque, how its node operations work, what node(index) really costs, and how to reverse linked lists in both library code and interview code. Interviewers ask this because the class looks easy, but the real test is whether you can separate pointer rewiring from finding the position.
Below the line (out of scope)
- Choosing between list implementations in detail: ArrayList vs LinkedList
- Array-backed lists: How ArrayList works
- Queue and stack defaults: Queue, Deque and ArrayDeque
- Iterator fail-fast behaviour: Fail-fast vs fail-safe iterators
The 30-second answer
Java's LinkedList is a doubly linked list. Internally it has first, last, size, and nodes shaped like Node<E> { E item; Node<E> next; Node<E> prev; }. Adding or removing at either end is O(1), and inserting next to a ListIterator you already hold is O(1), because it only changes pointers. But get(i), add(i, e) and remove(i) first call node(i), which walks from first or last depending on whether i < size >> 1, so indexed operations are O(n). It implements List and Deque, not RandomAccess. In practice, the extra node objects, pointer chasing and cache misses mean ArrayList usually wins unless you already have the iterator position or need deque operations with null elements.
What you’ll learn
- Draw Java
LinkedListas **doubly linkedNode<E>objects** withfirst,lastandsize - Explain
linkFirst,linkLast,linkBefore,unlinkand why indexed access usesnode(index) - Compare
LinkedListas aListand as aDeque, including why it does not implementRandomAccess - Reverse a linked list with
Collections.reverse,descendingIterator, Java 21reversed()and hand-written node algorithms - Use a
ListIteratorfor O(1) insertion at an existing cursor and know when the walk still costs O(n) - Estimate per-node memory cost and explain pointer chasing, cache misses and why ArrayList often wins
Interview radar
Asked often: Explain how LinkedList works internally, why random access is slow, and how you reverse a linked list.
Senior rounds probe: Why middle insertion is not automatically O(1), what Java 21's reversed() returns, and why memory layout beats Big-O tables in real workloads.
Production angle: A service stores millions of small entries in a LinkedList and spends more time chasing pointers and collecting node objects than doing useful work.
01Picture it first: a train with two station signs
A Java LinkedList is not one big object containing all elements. It is a small list object that points to a chain of node objects. The list object keeps two station signs, first and last, so operations at either end do not need a scan.
A LinkedList object stores first, last and size, and each node points to its previous and next node in a doubly linked chain
Notice three things in the picture. Each element has its own wrapper node. The arrows go both ways, so removing a node can stitch its neighbours together. There is no array index to jump through, so reaching node 7 means walking node by node.
02LinkedList under the hood
The shape below is simplified from OpenJDK, but it keeps the important fields. The real class also has modCount from AbstractList, used by fail-fast iterators.
Try it yourself first
Before reading the notes, answer this: which operations in the code below need to walk through the list, and which only touch the ends?
import java.util.LinkedList;
import java.util.ListIterator;
LinkedList<String> queue = new LinkedList<>();
queue.addLast("auth");
queue.addLast("payment");
queue.addFirst("edge");
String head = queue.removeFirst(); // edge
String middle = queue.get(1); // payment, found by walking
ListIterator<String> it = queue.listIterator(1);
it.add("fraud-check"); // insert at cursor
System.out.println(queue); // [auth, fraud-check, payment]
Notice the split. addFirst, addLast, removeFirst and removeLast are O(1). get(1) and listIterator(1) must find the indexed node first. Once the iterator is sitting at the cursor, it.add(...) is O(1).
The internal node is this idea:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E item, Node<E> next) {
this.item = item;
this.next = next;
this.prev = prev;
}
}
The main list object has three fields that matter for structure: first, last and size. These work together through four primitive operations.
| Operation | What it changes | Cost |
|---|---|---|
linkFirst(e) |
create a node before old first, update first, maybe last |
O(1) |
linkLast(e) |
create a node after old last, update last, maybe first |
O(1) |
linkBefore(e, succ) |
create a node between succ.prev and succ |
O(1) after succ is known |
unlink(x) |
detach x, connect x.prev to x.next, clear fields |
O(1) after x is known |
Here is a readable version of linkBefore. The important phrase is after succ is known.
private void linkBefore(E item, Node<E> succ) {
Node<E> pred = succ.prev;
Node<E> newNode = new Node<>(pred, item, succ);
succ.prev = newNode;
if (pred == null) {
first = newNode;
} else {
pred.next = newNode;
}
size++;
}
This is where many Big-O explanations go wrong. Inserting beside a node is O(1). Inserting at index 50_000 is not, because Java must first locate index 50_000.
The node(index) trick: walk from the nearer end
LinkedList does not always start from the head. If the index is in the first half, it walks forward from first; otherwise it walks backward from last.
Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++) x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--) x = x.prev;
return x;
}
}
For a list of 1,000,000 elements, get(10) walks 10 links, while get(999_990) walks 9 links backward. get(500_000) still walks about 500,000 links. The optimisation halves the worst walk, but it does not make indexed access constant time.
Many candidates say, "LinkedList is O(1) for middle insertions." That is only true if you already hold the node or a ListIterator at that position. If the API call is list.add(index, value), the list first pays O(n) to reach the index, then O(1) to relink.
03List, Deque and the missing RandomAccess marker
LinkedList implements List<E> and Deque<E>. As a List, it preserves insertion order, permits duplicates, permits null, and exposes indexed methods like get, set, add(index, e) and remove(index). As a Deque, it supports queue and stack methods at both ends: addFirst, addLast, removeFirst, removeLast, offer, poll, push, pop and peek.
It does not implement RandomAccess. That marker tells algorithms, "indexed access is cheap." ArrayList implements it; LinkedList does not. Library code can use that signal to choose an indexed loop for array-backed lists and an iterator walk for linked lists.
static long sum(List<Integer> values) {
long total = 0;
if (values instanceof java.util.RandomAccess) {
for (int i = 0; i < values.size(); i++) total += values.get(i);
} else {
for (int value : values) total += value;
}
return total;
}
That branch is not about style. On a LinkedList, for (int i = 0; i < n; i++) list.get(i) is O(n^2), because every get(i) starts a new walk.
I once reviewed a batch job that loaded about 600,000 IDs into a LinkedList, then used an index loop because it wanted progress logging every 10,000 rows. The code looked harmless and passed tests with 100 IDs. In production it spent minutes walking the same links again and again. Switching to an enhanced for loop fixed the algorithm; switching the storage to ArrayList fixed the memory and cache behaviour too.
Premium lesson
Keep reading with the Java Pass
The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.
- Reversing a LinkedList in Java
- Performance and memory cost
- How to say it in the interview
From ₹199 · one-time payment · No auto-renewal