26. Static Members and Inner Classes
static fields and methods belong to the class, not instances; static nested classes don't hold a reference to the outer instance; non-static inner classes do โ and that hidden reference is a memory-leak trap.
Explanation
static fields are shared across all instances of the class (one copy per class, not per object). static methods cannot access instance fields or this. Static initialiser blocks (static { ... }) run once when the class is loaded.
A static nested class (static class Inner) is logically nested inside the outer class for namespace purposes but does not have implicit access to the outer instance. It can be instantiated independently: new Outer.Inner().
A non-static inner class holds an implicit reference to its enclosing outer instance (Outer.this). This means it cannot outlive the outer object, and if the inner class escapes (stored in a long-lived collection), it accidentally keeps the outer object alive โ a classic memory leak pattern. Prefer static nested classes unless you genuinely need the outer reference.
Example
import java.util.ArrayList;
import java.util.List;
public class StaticAndInner {
private static int instanceCount = 0; // class-level counter
private final int id;
StaticAndInner() { this.id = ++instanceCount; }
public static int getCount() { return instanceCount; } // static method
// Static nested class โ no outer reference
static class Builder {
private String config = "default";
Builder withConfig(String c) { this.config = c; return this; }
StaticAndInner build() { return new StaticAndInner(); }
@Override public String toString() { return "Builder[" + config + "]"; }
}
// Non-static inner class โ holds implicit Outer.this reference
class EventHandler {
void handle() {
// Can access outer instance's fields
System.out.println("Handling event for instance #" + id);
}
}
public static void main(String[] args) {
StaticAndInner a = new StaticAndInner();
StaticAndInner b = new StaticAndInner();
System.out.println("Count: " + StaticAndInner.getCount()); // 2
// Static nested: instantiated without outer instance
Builder builder = new StaticAndInner.Builder().withConfig("prod");
System.out.println(builder);
// Non-static inner: requires outer instance
EventHandler handler = a.new EventHandler();
handler.handle(); // "Handling event for instance #1"
// Memory-leak risk: storing inner class in a list keeps 'a' alive
List<EventHandler> handlers = new ArrayList<>();
handlers.add(a.new EventHandler()); // 'a' cannot be GC'd while handler is alive
}
}Sources
- https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html โ Nested classes tutorial
- https://docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html โ Inner classes