Inner Classes & Anonymous Classes

Learn Java's four kinds of nested class — static nested, non-static inner, local, and anonymous — when each one fits, and when a lambda is the better tool.

Learn Inner Classes & Anonymous Classes in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…

Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

This lesson builds on a few earlier ones. You should be comfortable with:

Picture a house. A non-static inner class is a room inside the house — it can see the house's address and shares its plumbing, and it cannot exist without the house around it. A static nested class is a detached garage in the same plot: grouped with the house and built by the same architect, but it stands on its own and knows nothing about who lives inside.

A local class is a pop-up tent you put up for one job and take down when the job is done — it exists only for the length of one method. An anonymous class is a one-time contractor you hire on the spot without a name on the books. And a lambda is sending a quick text instead of hiring anyone at all — the right move when the job is a single small task.

A static nested class is a class declared inside another class and marked static . The static keyword here does not mean "shared" the way a static field does — it means "no link to an enclosing instance ". It is really just a normal top-level class that lives inside another for organisation, so you create it with the outer name as a prefix and no outer object is needed .

Use it for helpers that conceptually belong to the outer class but do not need any of its instance data — a Point inside a Shape , a Result inside a Calculator , or the classic Builder inside the thing it builds. Read the comments below.

A non-static inner class (also called a member class ) drops the static keyword. Now every inner instance is bound to one specific instance of the enclosing class and carries a hidden reference to it. That lets the inner class read and write the outer object's fields directly, as if they were its own.

Because an inner instance needs an enclosing instance, you cannot write new Inner() from outside — you write outer.new Inner() . When a name in the inner class is ambiguous, the qualified form Outer.this.field always means "the field on the enclosing object".

A non-static inner instance must be created from its enclosing object. Fill in the blank so Car is built from the Garage you already have. The expected output is in the comment — run it and check.

A local class is declared inside a method and is visible only there. It is handy when a small helper is needed in exactly one place. Like inner classes, it can use local variables from the surrounding method — but only ones that are effectively final (assigned once and never changed), because the value is captured by copy.

An anonymous class goes one step further: it is an unnamed class defined and instantiated in a single expression. The classic use was implementing a one-method interface like Comparator on the spot. Today a lambda does the same job with far less noise — so for any functional interface (exactly one abstract method), prefer the lambda. Keep anonymous classes for the cases a lambda cannot cover: extra fields, multiple methods, or extending a class.

Runnable is a functional interface — one method, run() , with no arguments and no return value. Rewrite the verbose anonymous class as a lambda by filling in the two blanks. Compare with the expected output in the comment.

Default to a static nested class . Only drop static when the helper truly needs to reach into the enclosing instance, and reach for a lambda whenever you are implementing a single-method interface.

* A linked-list Node is usually static nested: it carries its own data and doesn't need the list instance.

Here is the leak in miniature. A long-lived EventBus keeps a callback alive for the whole program. If that callback is a non-static inner Handler , it secretly pins the entire Screen it came from, so the garbage collector can never reclaim the screen. The static SafeHandler holds only the small String it needs, so the big object is free to go. Same output — very different memory behaviour.

Time to fly solo. The starter below has only a comment outline — no filled-in logic. Add a non-static inner class that implements Iterator<String> and reads the enclosing Bag 's items and size fields, then return one from iterator() . The expected output is in the comments.

You can now choose between Java's four nested classes with confidence: a static nested class for an independent helper, a non-static inner class when you need the enclosing instance (created with outer.new Inner() ), a local class for one method, and an anonymous class only when a lambda can't do the job. You also know how a hidden outer reference leaks memory — and how to stop it.

Next: Exception Handling Architecture — custom hierarchies, chained exceptions, and error strategies.

Practice quiz

What does the static keyword mean on a static nested class?

  • The class is shared across all instances like a static field
  • The class has no link to an instance of the enclosing class
  • The class can only be created once
  • All of the class's methods are static

Answer: The class has no link to an instance of the enclosing class. A static nested class has no implicit reference to an enclosing instance, so you create it with new Outer.Nested() and no outer object is needed.

How do you create an instance of a non-static inner class from outside?

  • new Outer.Inner()
  • new Inner()
  • outer.new Inner()
  • Outer.Inner.new()

Answer: outer.new Inner(). A non-static inner instance needs an enclosing instance, so you write outer.new Inner(). Writing new Outer.Inner() fails to compile.

Inside a non-static inner class, what does the bare name of an outer field like count refer to?

  • A copy of the field made when the inner object was created
  • Outer.this.count — the field on the enclosing instance
  • A new field local to the inner class
  • A static field shared by all inner instances

Answer: Outer.this.count — the field on the enclosing instance. An unqualified outer name resolves to the enclosing instance's field, equivalent to Outer.this.count, so the inner class can read and write it directly.

Why can a non-static inner class cause a memory leak?

  • It allocates a large hidden buffer
  • It holds an implicit reference to its enclosing instance, keeping it alive
  • It never runs its finalizer
  • It duplicates every outer field

Answer: It holds an implicit reference to its enclosing instance, keeping it alive. The hidden outer reference means anything keeping the inner object alive (like a long-lived listener) also pins the whole enclosing object, so the GC cannot reclaim it.

When should you prefer a lambda over an anonymous class?

  • When implementing a functional interface (one abstract method)
  • When you need several methods or instance fields
  • When you must extend a concrete class
  • When you need a new 'this' reference

Answer: When implementing a functional interface (one abstract method). Lambdas concisely implement single-method (functional) interfaces. Anonymous classes are for cases a lambda can't express: extra fields, multiple methods, or extending a class.

Which kinds of local variables can a local or anonymous class capture?

  • Any local variable
  • Only static fields
  • Only effectively final variables (assigned once, never changed)
  • Only variables declared with the final keyword explicitly

Answer: Only effectively final variables (assigned once, never changed). Captured locals must be effectively final because the value is copied; allowing reassignment would let the copies disagree.

What is a local class?

  • A class defined in a separate file in the same package
  • A class declared inside a method, visible only there
  • A class marked with the local keyword
  • A nested class that is always static

Answer: A class declared inside a method, visible only there. A local class is declared inside a method (or block) and is only visible within that method, useful for a named helper needed in exactly one place.

What does Outer.this refer to inside a non-static inner class?

  • The inner class object itself
  • The class object of Outer
  • The enclosing Outer instance
  • A static singleton of Outer

Answer: The enclosing Outer instance. Outer.this explicitly names the enclosing instance, which is how you disambiguate a shadowed field name.

For a linked-list Node that carries its own data and doesn't need the list instance, which nesting is best?

  • Non-static inner class
  • Static nested class
  • Local class
  • Anonymous class

Answer: Static nested class. A Node usually doesn't need the enclosing list instance, so a static nested class is the right default — it avoids a needless outer reference.

Which statement about a lambda's 'this' is correct?

  • A lambda introduces its own new 'this'
  • A lambda's 'this' is the enclosing instance, not the lambda object
  • A lambda has no access to 'this'
  • A lambda's 'this' is always null

Answer: A lambda's 'this' is the enclosing instance, not the lambda object. Unlike an anonymous class, a lambda does not create a new 'this'; its 'this' refers to the enclosing instance.