Declaring Node as a Static Nested Class
Try This First
You write private class Node<T> inside your LinkedList class (no static). Your list holds a million nodes. What hidden cost does every single node carry?
Reveal
Every node holds an invisible reference back to the LinkedList instance that created it. That is one extra object reference per node, and it prevents the garbage collector from freeing the outer list as long as any node is still reachable.
What You Need To Walk In With
- A nested class declared without
staticis a non-static inner class. Every instance of it silently stores a reference to the enclosing object. - Adding
staticto a nested class severs that hidden link. The nested class is scoped inside the outer class for naming purposes only. Node<T>does not need to call any method on its LinkedList container, so it should bestatic.- Making Node
privatehides the implementation detail from callers and protects the list’s invariants. - The full nested-class taxonomy (anonymous, local, non-static inner) is covered later, in the inner-classes material.
How It Works
Inside your LinkedList class, the Node declaration looks like this:
public class LinkedList<E> {
private static class Node<T> {
T data;
Node<T> next;
Node(T data) {
this.data = data;
this.next = null;
}
}
private Node<E> head;
private int size;
}
The word static on line 3 is the critical detail. Without it, Java treats Node as a non-static inner class: every new Node<>(value) call would attach an invisible LinkedList.this pointer to the new object. That pointer:
- consumes memory on every node (one reference, multiplied across every element in the list),
- blocks the outer LinkedList from being garbage-collected as long as any node is live, and
- can cause surprises when serializing nodes independently.
Because Node is purely a data-holder (two fields, one constructor, no need to reach back into LinkedList), the right declaration is private static class Node<T>.
A pointer sketch for a three-element list with static Node:
head
|
[A | -]-->[B | -]-->[C | null]
Each box = one Node<T>. No arrow points back to the LinkedList.
Compare that to the non-static case (do not write this):
head
|
[A | - | *LL]-->[B | - | *LL]-->[C | null | *LL]
^---- hidden ref to LinkedList present in every node
The *LL slot is the implicit enclosing-instance reference Java injects for non-static inner classes. Making Node static removes it entirely.
Worked Example: Predict, Then Check
Read this declaration and predict what the compiler will do:
public class Stack<E> {
private class Node<T> { // no static
T data;
Node<T> next;
}
private Node<E> head;
}
Does this compile? If it does, what is the runtime cost compared to a static version?
Reveal
It compiles without error. Java allows non-static inner classes. However, at runtime each Node instance carries a hidden reference to its enclosing Stack instance. A stack with 10,000 elements will have 10,000 invisible Stack.this pointers, one per node, consuming extra heap and preventing the Stack from being garbage-collected while any node is reachable. The fix is to add static.
A Common Mistake
A common mistake is to drop static and write private class Node<T> because the inner class still compiles and the tests may all pass. The problem is invisible: each node silently holds a reference to the enclosing LinkedList. In a list with a large number of elements, this multiplies into significant extra memory. Worse, if you ever hold a reference to a single node (for example, in a cursor or iterator), the entire LinkedList is kept alive by the garbage collector even after all other references to the list are gone. The fix is straightforward: add static to every data-structure helper class that does not need to call methods on its container. (Source: Bloch EJ3 Item-24)
Go Deeper (optional)
Once you are comfortable with private static class Node<T>, it is worth noting the Big-O implication: removing the hidden reference field costs nothing algorithmically (it does not change O(n) traversal), but it matters in practice for memory-constrained systems or very large lists. The inner-classes material covers the full nested-class taxonomy if you want to understand exactly when a non-static inner class is the right choice, such as iterators that do need to call back into the outer collection.
Check Yourself
Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.
Check your understanding
In private static class Node<T> declared inside LinkedList, what does static prevent?
Why should the Node class be declared private rather than public?
A LinkedList with private class Node<T> (no static) holds 50,000 elements. How many hidden enclosing-instance references exist at runtime?
Which declaration is correct for a data-only Node helper inside a LinkedList that does not need to call any LinkedList methods?
If you remove static from Node and then hold a reference to a single Node after removing all other references to its LinkedList, what happens to the LinkedList in memory?