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