All topics
library
intermediate

Inner Classes: Static, Member, Local, Anonymous

Know the four types of inner classes, when each is appropriate, and their relationship to the enclosing instance.

Four kinds of nested class, and the one difference that matters is whether it holds the enclosing instance.

Static nested = a tenant in an office building (uses the address but has their own key, doesn't need the landlord). Member inner = a personal assistant (always tied to a specific boss, has access to the boss's office).

Key Concepts

1
    class Outer {
      static class Nested { }           // 1. no outer reference
      class Member { }                  // 2. holds Outer.this
2
      void m() {
        class Local { }                 // 3. inside a method
        Runnable r = new Runnable() {   // 4. anonymous
          public void run() { }
        };
      }
    }
3
1. Static nested is a top-level class that happens to live inside another for naming. Map.Entry is the familiar example. This is the default choice.
Map.Entry
4
2. Member inner holds a hidden reference to the outer object, which is how it reads outer fields including private ones:
5
    class Outer {
      private int x = 1;
      class Member { int get() { return x; } }    // reaches Outer.this.x
    }
6
    Outer.Member m = new Outer().new Member();    // needs an outer instance
7
That hidden reference is a memory leak waiting to happen.
    class Activity {
      class Handler { }                 // holds the whole Activity
8
      void register() { registry.add(new Handler()); }   // Activity now immortal
    }
9
The registry keeps the Handler, the Handler keeps the Activity, and nothing can be collected. Adding static to Handler fixes it.
HandlerActivitystatic
10
3. Local is declared inside a method and can read effectively final locals. Rare now — a lambda does the same job in a line.
11
4. Anonymous declares and instantiates in one expression. It was the standard way to write a callback before Java 8:
12
    list.sort(new Comparator<String>() {
      public int compare(String a, String b) { return a.length() - b.length(); }
    });
13
    list.sort(Comparator.comparingInt(String::length));     // today
14
Anonymous classes still have their uses, because a lambda cannot extend a class or declare several methods. An anonymous subclass can, and it also records its generic type — which is how TypeReference works.
TypeReference
15
The rule: prefer static unless you genuinely need the enclosing instance.
static
16
What the interviewer is probing.1. "Why prefer a static nested class?" Probing: the memory leak. Stalls: "Style." *Moves up:* a non-static inner class holds a hidden reference to the enclosing instance, so if the inner object outlives the outer one, the outer cannot be collected.
17
2. "What can a local class capture from the enclosing method?" Probing: capture rules. Stalls: "Everything." Moves up: only effectively final locals, because the captured value is copied and the class may outlive the method frame.
18
3. "What does this refer to inside an anonymous class versus a lambda?" Probing: a real behavioural difference when migrating. Stalls: "The same thing." Moves up: in an anonymous class this is the anonymous instance; in a lambda it is the enclosing object.
19
4. "When is an anonymous class still the right choice over a lambda?" Probing: the limits of lambdas. Stalls: "Never, lambdas replaced them." Moves up: when you need to extend a class, implement several methods, or record a generic type as TypeReference does.