Java Inner Classes

Classes defined inside other classes

🏠 What are Inner Classes?

Inner classes are classes defined inside another class. They can access outer class members and provide better encapsulation by grouping related functionality together.


class OuterClass {
    private String message = "Hello from Outer";
    
    class InnerClass {
        public void display() {
            System.out.println(message);  // Access outer class member
        }
    }
}
                                    

Output:

Inner class can access outer class members

Types of Inner Classes

🏠

Member Inner Class

Regular inner class inside outer class

class Outer {
    class Inner { }
}

Static Inner Class

Inner class that doesn't need outer instance

class Outer {
    static class StaticInner { }
}
📍

Local Inner Class

Class defined inside a method

void method() {
    class LocalInner { }
}
👤

Anonymous Class

Class without a name, defined inline

new Interface() {
    // Implementation
};

🔹 Member Inner Class

A regular inner class that has access to all outer class members:

class Computer {
    private String brand = "Dell";
    private boolean isOn = false;
    
    public void turnOn() {
        isOn = true;
        System.out.println(brand + " computer is now ON");
    }
    
    // Member inner class
    class Processor {
        private String type = "Intel i7";
        
        public void process() {
            if(isOn) {  // Access outer class variable
                System.out.println(type + " processor is processing on " + brand);
            } else {
                System.out.println("Computer is OFF. Turn it on first!");
            }
        }
        
        public void showComputerInfo() {
            System.out.println("Computer brand: " + brand);  // Direct access
            turnOn();  // Call outer class method
        }
    }
    
    public void createProcessor() {
        Processor processor = new Processor();
        processor.process();
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        Computer computer = new Computer();
        
        // Create inner class instance
        Computer.Processor processor = computer.new Processor();
        processor.process();
        processor.showComputerInfo();
        processor.process();
    }
}

Output:

Computer is OFF. Turn it on first!
Computer brand: Dell
Dell computer is now ON
Intel i7 processor is processing on Dell

🔹 Static Inner Class

Static inner classes don't need an outer class instance:

class University {
    private String name = "MIT";
    private static String country = "USA";
    
    // Static inner class
    static class Department {
        private String deptName;
        
        public Department(String deptName) {
            this.deptName = deptName;
        }
        
        public void showInfo() {
            // Can access static outer class members
            System.out.println("Department: " + deptName);
            System.out.println("Country: " + country);
            
            // Cannot access non-static outer class members
            // System.out.println(name);  // This would cause error
        }
        
        public static void showCountry() {
            System.out.println("All universities in: " + country);
        }
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        // Create static inner class without outer instance
        University.Department dept = new University.Department("Computer Science");
        dept.showInfo();
        
        // Call static method
        University.Department.showCountry();
    }
}

Output:

Department: Computer Science
Country: USA
All universities in: USA

🔹 Local Inner Class

Classes defined inside methods or blocks:

class Calculator {
    public void performOperation(String operation, int a, int b) {
        // Local inner class
        class Operation {
            public void calculate() {
                switch(operation.toLowerCase()) {
                    case "add":
                        System.out.println(a + " + " + b + " = " + (a + b));
                        break;
                    case "multiply":
                        System.out.println(a + " × " + b + " = " + (a * b));
                        break;
                    default:
                        System.out.println("Unknown operation");
                }
            }
        }
        
        // Use local inner class
        Operation op = new Operation();
        op.calculate();
    }
}

// Usage
Calculator calc = new Calculator();
calc.performOperation("add", 5, 3);
calc.performOperation("multiply", 4, 7);

Output:

5 + 3 = 8
4 × 7 = 28

🔹 Anonymous Inner Class

Classes without names, often used for interfaces or abstract classes:

// Interface
interface Greeting {
    void sayHello(String name);
}

public class AnonymousExample {
    public static void main(String[] args) {
        // Anonymous inner class implementing interface
        Greeting greeting = new Greeting() {
            @Override
            public void sayHello(String name) {
                System.out.println("Hello, " + name + "! Nice to meet you.");
            }
        };
        
        greeting.sayHello("Alice");
        
        // Another anonymous class with different implementation
        Greeting formalGreeting = new Greeting() {
            @Override
            public void sayHello(String name) {
                System.out.println("Good day, Mr./Ms. " + name + ".");
            }
        };
        
        formalGreeting.sayHello("Smith");
    }
}

Output:

Hello, Alice! Nice to meet you.
Good day, Mr./Ms. Smith.

🔹 When to Use Inner Classes

  • Logical grouping: When a class is only used by one other class
  • Encapsulation: To hide implementation details
  • Access to private members: When you need access to outer class privates
  • Event handling: Common in GUI applications
  • Callbacks: Anonymous classes for one-time implementations

🧠 Test Your Knowledge

Which type of inner class can access outer class private members?