W3docs

Java Nested Classes

Nested classes in Java: static nested classes, inner classes, local classes, and anonymous classes.

Java lets you declare a class inside another class. The umbrella term is nested class, and Java offers four flavors, divided by where they live and whether they carry a reference to an enclosing instance:

FlavorWhere it's declaredCarries enclosing this?Chapter
Static nested classInside a class body, with staticNothis chapter
Inner classInside a class body, no staticYesinner classes
Local classInside a method bodyYes (if non-static method)local classes
Anonymous classAn on-the-spot subclass/implementationYes (if non-static context)anonymous classes

The reason to pick a nested class over a separate top-level one is scope — the nested class is only useful in the context of its enclosing class and shouldn't be exposed to the rest of the codebase. This chapter is the overview; each kind gets its own deeper treatment in the chapters that follow.

Why nest classes at all?

Three main motivations:

  • Logical grouping. A Map.Entry only makes sense inside a Map. Nesting it makes that relationship obvious in the code.
  • Encapsulation. A nested class can be made private so nothing outside the enclosing class can even reference it.
  • Closures over enclosing state. An inner / local / anonymous class can read the enclosing instance's fields and method-local variables, which is the foundation of event handlers, iterators, and lots of small adapter patterns.

If none of these apply, write a top-level class.

Static nested classes

A class marked static inside another class is a static nested class:

public class Outer {
  static class Inner {
    void hi() { System.out.println("hi"); }
  }
}

Outer.Inner i = new Outer.Inner();    // instantiate directly
i.hi();

A static nested class is just a top-level class that happens to live inside Outer's namespace. It has no implicit reference to an Outer instance — you can use it without ever creating one. The only difference from a top-level class is the scoping: Outer.Inner is the qualified name.

This is the variant you've already seen all through Parts 5 and 6 — every static class Foo {} in a RunnableJava example is one of these. The reason we used static was so we could instantiate them from a static main without needing an Outer instance.

Inner classes (non-static nested)

Drop the static and you get an inner class. The inner class instance is bound to an instance of the outer class, carrying an implicit reference to it:

public class Outer {
  int x = 1;
  class Inner {                       // no static
    int get() { return x; }           // reads Outer's x through the implicit reference
  }
}

Outer       o = new Outer();
Outer.Inner i = o.new Inner();        // unusual syntax — bind to o
System.out.println(i.get());           // 1

The funny o.new Inner() is how you create an inner-class instance bound to a specific outer instance. Inner classes can't have static members (older rule; relaxed in Java 16+ to allow static members in inner classes). Covered fully in inner classes.

Local classes

A class declared inside a method body is local — scoped to that method:

public void run() {
  class Step { int n; Step(int n) { this.n = n; } }     // visible only in run()

  Step s = new Step(5);
}

Useful for tiny helpers that don't deserve a top-level class or even a class-level nested one. They have access to the enclosing method's final (or effectively final) variables. The local classes chapter has the full story.

Anonymous classes

An anonymous class is a one-shot subclass or interface implementation defined inline at the point of use:

Runnable r = new Runnable() {
  @Override
  public void run() { System.out.println("hi"); }
};

That's a single expression that (1) defines a new class implementing Runnable, (2) creates an instance of it, (3) assigns it to r. The class has no name — it exists only here. Almost all use cases for anonymous classes have been replaced by lambdas in modern Java, but they're still legal and occasionally useful. See anonymous classes.

Choosing the right kind

A quick decision tree:

  1. Does the nested class need a reference to an outer instance? If no → static nested class. If yes → some non-static variant.
  2. Is it used inside a single method? If yes → local or anonymous. If no → inner.
  3. Is it a one-shot subclass/interface impl with one or two methods? If yes → lambda (preferred) or anonymous class (legacy).

Static nested classes are by far the most common. Inner classes show up for iterator-style adapters. Local and anonymous classes are rarer in modern code — lambdas eat most of their use cases.

Naming and access

Nested classes can carry any access modifier — public, private, protected, package-private — and the modifier rules are the same as for top-level members. Map.Entry is public; a private static class Node inside a LinkedList implementation is invisible to the outside world.

Compiled nested classes get $-separated names in the .class files: Outer$Inner, Outer$1. You'll see these in stack traces and debuggers occasionally.

A worked example

java— editable, runs on the server

What's next

The next three chapters dig into each of the non-static kinds. First up: inner classes, the most general — a class bound to an enclosing instance.

Practice

Practice

Which kind of nested class does NOT carry an implicit reference to an enclosing-class instance?