Nested Classes
Inner classes, static nested classes
6 min read
Nested Classes in Java
A nested class is a class defined inside another class. Java has four types of nested classes, each with different use cases.
Types of Nested Classes
- Static Nested Class: Like a regular class, but inside another
- Inner Class (Non-static): Associated with outer instance
- Local Class: Defined inside a method
- Anonymous Class: No name, defined inline
🔑 Key Difference: Inner class needs outer instance (has access to outer's members). Static nested class doesn't need outer instance.
💡 Best Practice: Prefer static nested class unless you specifically need access to outer instance's members.
Code Examples
Static nested class - independent of outer instance
java
1// Static Nested Class - doesn't need outer instance
2public class Outer {
3 private static String staticField = "Static";
4 private String instanceField = "Instance";
5
6 // Static nested class
7 public static class StaticNested {
8 public void display() {
9 // Can access outer's static members
10 System.out.println(staticField); // OK
11 // System.out.println(instanceField); // ERROR!
12 }
13 }
14}
15
16// Usage - no outer instance needed
17Outer.StaticNested nested = new Outer.StaticNested();
18nested.display();
19
20// Common use: Builder pattern
21public class User {
22 private final String name;
23 private final int age;
24
25 private User(Builder builder) {
26 this.name = builder.name;
27 this.age = builder.age;
28 }
29
30 public static class Builder { // Static nested
31 private String name;
32 private int age;
33
34 public Builder name(String name) {
35 this.name = name;
36 return this;
37 }
38
39 public Builder age(int age) {
40 this.age = age;
41 return this;
42 }
43
44 public User build() {
45 return new User(this);
46 }
47 }
48}
49
50User user = new User.Builder().name("Alice").age(25).build();Inner class - tied to outer instance
java
1// Inner Class (Non-static) - needs outer instance
2public class Outer {
3 private String outerField = "Outer data";
4
5 // Inner class - associated with outer instance
6 public class Inner {
7 private String innerField = "Inner data";
8
9 public void display() {
10 // Can access outer's instance members!
11 System.out.println(outerField); // Outer data
12 System.out.println(innerField); // Inner data
13
14 // Access outer's this
15 System.out.println(Outer.this.outerField);
16 }
17 }
18
19 public void createInner() {
20 Inner inner = new Inner(); // this.new Inner()
21 inner.display();
22 }
23}
24
25// Usage - requires outer instance first
26Outer outer = new Outer();
27Outer.Inner inner = outer.new Inner(); // Syntax!
28inner.display();
29
30// Or from within outer class method
31outer.createInner();Local class - defined within a method
java
1// Local Class - defined inside a method
2public class Outer {
3 public void process(String input) {
4 final String localVar = "Local";
5
6 // Local class - only visible in this method
7 class LocalProcessor {
8 void run() {
9 System.out.println(input); // Method param
10 System.out.println(localVar); // Local variable
11 }
12 }
13
14 LocalProcessor processor = new LocalProcessor();
15 processor.run();
16 }
17}
18
19// Variables used in local class must be effectively final
20public void example() {
21 int x = 10;
22
23 class Local {
24 void show() {
25 System.out.println(x); // OK - x is effectively final
26 }
27 }
28
29 // x = 20; // Would make x not effectively final
30 // causing compile error in Local class
31
32 new Local().show();
33}Real-world nested class usage
java
1// Real-world Example: Event Handling with Inner Class
2public class Button {
3 private String label;
4 private ClickListener listener;
5
6 public Button(String label) {
7 this.label = label;
8 }
9
10 public void setClickListener(ClickListener listener) {
11 this.listener = listener;
12 }
13
14 public void click() {
15 if (listener != null) {
16 listener.onClick(label);
17 }
18 }
19
20 public interface ClickListener {
21 void onClick(String source);
22 }
23}
24
25public class GUI {
26 private int clickCount = 0;
27
28 public void setup() {
29 Button btn = new Button("Submit");
30
31 // Anonymous inner class - most common
32 btn.setClickListener(new Button.ClickListener() {
33 @Override
34 public void onClick(String source) {
35 clickCount++; // Access outer's field
36 System.out.println(source + " clicked " + clickCount + " times");
37 }
38 });
39
40 btn.click(); // Submit clicked 1 times
41 btn.click(); // Submit clicked 2 times
42 }
43}Use Cases
- Static nested: Builder pattern, helper classes
- Inner class: Event handlers, callbacks
- Inner class: Iterators accessing collection state
- Local class: One-time use within method
- Grouping related classes together
- Encapsulating implementation details
Common Mistakes to Avoid
- Using inner when static nested is sufficient
- Memory leaks from inner class holding outer ref
- Confusing static nested vs inner syntax
- Local class using non-final variables
- Over-nesting classes (reduces readability)
- Not understanding outer.this access