Java Inner Classes
Introduction to Inner Classes
Inner classes (also called nested classes) are classes defined within another class. They are used to logically group classes that are only used in one place, increase encapsulation, and make code more readable and maintainable.
Java supports four types of nested classes:
1. Member inner classes
2. Static nested classes
3. Local inner classes
4. Anonymous inner classes
Types of Inner Classes
Type | Description | Access Modifiers |
---|---|---|
Member Inner Class | Defined at the same level as instance variables | Can use any access modifier |
Static Nested Class | Defined with static modifier | Can use any access modifier |
Local Inner Class | Defined inside a method or block | Cannot use access modifiers |
Anonymous Inner Class | Defined and instantiated simultaneously without a name | No access modifier |
Member Inner Class
A member inner class is defined at the member level of a class (same level as methods and instance variables). It has access to all members of the outer class, including private members.
class Outer {
private String outerField = "Outer field";
class Inner {
private String innerField = "Inner field";
public void display() {
System.out.println("Accessing outer field from inner class: " + outerField);
System.out.println("Inner field: " + innerField);
}
}
public void createInner() {
Inner inner = new Inner();
inner.display();
}
}
public class MemberInnerClassExample {
public static void main(String[] args) {
Outer outer = new Outer();
outer.createInner();
// Creating inner class from outside
Outer.Inner inner = outer.new Inner();
inner.display();
}
}
Accessing outer field from inner class: Outer field Inner field: Inner field Accessing outer field from inner class: Outer field Inner field: Inner field
Static Nested Class
A static nested class is defined with the static modifier. It cannot access non-static members of the outer class directly.
class Outer {
private static String staticField = "Static field";
private String instanceField = "Instance field";
static class StaticNested {
public void display() {
System.out.println("Accessing static field: " + staticField);
// Cannot access instanceField directly
// System.out.println(instanceField); // Error
}
}
}
public class StaticNestedExample {
public static void main(String[] args) {
// Creating static nested class without outer instance
Outer.StaticNested nested = new Outer.StaticNested();
nested.display();
}
}
Accessing static field: Static field
Local Inner Class
A local inner class is defined within a method or block. It can only be instantiated within that method or block and can access final or effectively final local variables.
class Outer {
private String outerField = "Outer field";
public void methodWithLocalClass() {
final String localVar = "Local variable"; // Must be final or effectively final
class LocalInner {
public void display() {
System.out.println("Outer field: " + outerField);
System.out.println("Local variable: " + localVar);
}
}
LocalInner local = new LocalInner();
local.display();
}
}
public class LocalInnerExample {
public static void main(String[] args) {
Outer outer = new Outer();
outer.methodWithLocalClass();
}
}
Outer field: Outer field Local variable: Local variable
Anonymous Inner Class
An anonymous inner class is defined and instantiated at the same time without a explicit class name. It's commonly used for implementing interfaces or extending classes with small modifications.
interface Greeting {
void greet();
}
class AnonymousInnerExample {
public static void main(String[] args) {
// Anonymous class implementing Greeting interface
Greeting greeting = new Greeting() {
@Override
public void greet() {
System.out.println("Hello from anonymous class!");
}
};
greeting.greet();
// Anonymous class extending Thread class
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("Thread running from anonymous class");
}
};
thread.start();
}
}
Hello from anonymous class! Thread running from anonymous class
Best Practices
- Use inner classes when they're logically part of the outer class and not needed elsewhere
- Prefer static nested classes when you don't need access to outer instance members
- Use anonymous classes for one-time implementations of interfaces or small extensions
- Be cautious with memory usage as non-static inner classes hold references to outer instances
- Consider using lambda expressions instead of anonymous classes for functional interfaces