Nested and Inner Classes
Define classes inside other classes: static nested classes, inner classes, local classes, and anonymous classes.
Overview
Key Points
- •A static nested class is like a top-level class but scoped inside another class
- •An inner class holds a reference to the outer class instance. Instantiate with: outer.new Inner()
- •Inner classes can access private members of the outer class
- •Local classes are defined and used inside a single method
- •Anonymous classes implement an interface or extend a class inline with no class name
- •Anonymous classes are useful for one-off implementations (event handlers, comparators)
- •With lambdas and method references (Java 8+), anonymous classes for functional interfaces are often replaced by lambdas
Examples
Static nested class
public class Main {
static class Builder {
private String name = "";
private int age = 0;
Builder name(String name) { this.name = name; return this; }
Builder age(int age) { this.age = age; return this; }
String build() { return name + " (age " + age + ")"; }
}
public static void main(String[] args) {
// Access static nested class without an outer instance
Builder b = new Builder();
String person = b.name("Alice").age(30).build();
System.out.println(person); // Alice (age 30)
}
}Static nested classes are accessed as OuterClass.NestedClass but here Builder is inside Main so it is just Builder. Use static nested classes when the class does not need access to the outer instance.
Inner class accessing outer members
public class Main {
private String secret = "top-secret";
class Insider {
void reveal() {
// Accesses outer instance's private field
System.out.println("The secret is: " + secret);
}
}
public static void main(String[] args) {
Main outer = new Main();
Main.Insider inner = outer.new Insider();
inner.reveal(); // The secret is: top-secret
}
}An inner class instance is always tied to an outer class instance. You must create the outer first, then call outer.new Inner(). Inner classes can access all outer fields and methods.
Anonymous class implementing an interface
import java.util.Arrays;
import java.util.List;
public class Main {
interface Greeter {
String greet(String name);
}
public static void main(String[] args) {
// Anonymous class implementing Greeter
Greeter formal = new Greeter() {
@Override
public String greet(String name) {
return "Good day, " + name + ".";
}
};
Greeter casual = new Greeter() {
@Override
public String greet(String name) {
return "Hey " + name + "!";
}
};
System.out.println(formal.greet("Alice")); // Good day, Alice.
System.out.println(casual.greet("Bob")); // Hey Bob!
// Sorting with an anonymous Comparator
List<String> words = Arrays.asList("banana", "apple", "cherry");
words.sort(new java.util.Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length(); // sort by length
}
});
System.out.println(words); // [apple, banana, cherry]
}
}Anonymous classes implement an interface or extend a class at the point of use. Since Greeter is a functional interface, it could also be written as a lambda: name -> "Hey " + name + "!".
Common Mistakes
- Creating an inner class instance without an outer instance. You need outer.new Inner(), not new Inner()
- Making an inner class static when it needs to access outer fields, or non-static when it does not. If the inner class does not need the outer instance, make it static to avoid memory leaks
- Using anonymous classes for functional interfaces when a lambda is shorter and more readable
Note
Prefer lambdas over anonymous classes when implementing a functional interface. Reserve anonymous classes for cases where you need to override multiple methods or add fields/state to the anonymous object.
Exercises
Write Java code and click Run to execute it instantly. When your output looks correct, mark as done.
Completed: 0 / 4 exercises
Knowledge Check
Question 1 of 4