Appearance
Lesson 07 · Nested & Inner Classes
Objectives
After this lesson you will be able to:
- Distinguish static nested, inner (non-static), local, and anonymous classes.
- Explain how each captures the enclosing instance and local variables.
- Use qualified
this(Outer.this) and reason about shadowing. - Know which nested types are implicitly static, and use the right nesting for the job.
The four kinds
| Kind | Declared | Needs an outer instance? | Can access outer instance members? |
|---|---|---|---|
| Static nested | as a static member | No | Only static ones |
| Inner (non-static) | as an instance member | Yes | Yes, including private |
| Local | inside a method | (lives in that method) | Yes (effectively final locals) |
| Anonymous | inline expression | — | Yes (effectively final locals) |
Static nested vs inner
A static nested class is just a top-level class scoped inside another — no link to an outer object. An inner class holds an implicit reference to an enclosing instance, so it can read its private members.
java
class Outer {
private int x = 10;
static class Nested { int sum(int a, int b) { return a + b; } } // no Outer needed
class Inner { int readX() { return x; } } // uses Outer.this.x
}
Outer.Nested n = new Outer.Nested(); // no Outer instance
Outer.Inner i = new Outer().new Inner(); // needs an Outer instanceExam trap
Creating an inner class needs an enclosing instance: the outer.new Inner() syntax. A static nested class is built with just new Outer.Nested(). Since Java 16, an inner class may declare static members (fields and methods) — the old "constants only" restriction is gone.
Qualified this and shadowing
When an inner class declares a member with the same name as an outer one, the inner name shadows it. Reach the outer instance explicitly with Outer.this.
java
class Outer {
int v = 1;
class Inner {
int v = 2;
int inner() { return v; } // 2 — the inner field
int outer() { return Outer.this.v; } // 1 — qualified this reaches the outer instance
}
}Local and anonymous classes
A local class is declared inside a method; an anonymous class is a local class with no name, declared and instantiated in one expression — to implement an interface or extend a class on the spot.
java
Runnable r = new Runnable() { // anonymous class implementing an interface
@Override public void run() { System.out.println("hi"); }
};
Thread t = new Thread() { // anonymous class EXTENDING a class
{ setName("worker"); } // instance initializer — an anonymous class has no constructor
@Override public void run() { }
};
interface Greeter { String greet(); }
Greeter g = () -> "hello"; // a lambda — lighter than an anonymous classGotcha
Local and anonymous classes may only capture local variables that are final or effectively final (never reassigned). Mutating a captured local — or trying to — is a compile error. They can freely read and mutate fields of the enclosing instance. An anonymous class can't declare a constructor; use an instance initializer block for setup.
Implicitly static nested types
A nested interface, enum, or record is implicitly static — it holds no reference to an enclosing instance, whether or not you write static.
java
class Container {
interface Listener { } // implicitly static
enum State { ON, OFF } // implicitly static
record Entry(int k) { } // implicitly static
}Choosing a nesting
- Static nested — a helper type tied to the outer class but not to an instance (most common).
- Inner — when instances genuinely belong to one outer instance and need its state.
- Local — a one-method helper, named for readability.
- Anonymous / lambda — a throwaway implementation; prefer a lambda for a functional interface, an anonymous class when you must extend a class or implement several methods.
Beyond the exam
A lambda has no this of its own — this inside a lambda refers to the enclosing instance, unlike an anonymous class, whose this is the anonymous object. Lambdas (Module 06) replace most anonymous classes for functional interfaces.
Key Takeaways
- Static nested: no outer instance (
new Outer.Nested()); sees only static outer members. - Inner (non-static): bound to an enclosing instance (
outer.new Inner()), sees its private members; since Java 16 it may declarestaticmembers. - Use
Outer.thisto reach a shadowed enclosing member from an inner class. - Local/anonymous classes capture only effectively final locals; they may mutate enclosing fields. An anonymous class extends a class or implements an interface inline and uses an instance initializer (no constructor).
- Nested interfaces/enums/records are implicitly static. Prefer a lambda over an anonymous class for a functional interface.
Lesson Quiz
How do you create an instance of a non-static inner class Inner of Outer?
Which local variables can an anonymous class capture?
A static nested class can access...
From an inner class, how do you read a field v of the enclosing Outer instance when the inner class also declares v?
Since Java 16, an inner (non-static) class may declare...
A nested record declared inside a class is...
Which can an anonymous class do?
Next: Pattern Matching. Run the matching code in labs/src/main/java/com/jse21/m03_oop/.