Nested Classes in Java
Introduction
In Java, you can define a class within another class. Such a class is known as a nested class. Nested classes are a powerful mechanism to logically group classes that are only used in one place, increase encapsulation, and create more readable and maintainable code.
Types of Nested Classes
Nested classes are divided into two main categories:
- Static Nested Classes
- Inner Classes (Non-static nested classes)
Inner classes are further divided into:
- Member Inner Classes
- Local Inner Classes
- Anonymous Inner Classes
1. Static Nested Classes
A static nested class is associated with its outer class, similarly to static methods or variables. It cannot access non-static members of the enclosing class directly; it must instantiate the outer class to access them.
public class OuterClass {
private static String staticData = "Static Data";
private String instanceData = "Instance Data";
public static class StaticNestedClass {
public void display() {
// Can access static members of the outer class
System.out.println(staticData);
// Cannot access non-static members directly:
// System.out.println(instanceData); // Error
}
}
}
Instantiation:
OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass();
nested.display();
2. Member Inner Classes
A member inner class is associated with an instance of the enclosing class. It has access to all members of the enclosing class, including private variables and methods.
public class OuterClass {
private String secret = "Inner classes can see me!";
public class InnerClass {
public void revealSecret() {
System.out.println(secret);
}
}
}
Instantiation: An inner class requires an instance of the outer class to be created.
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
inner.revealSecret();
3. Local Inner Classes
A local inner class is defined within a block, usually a method body. It is completely hidden from the outside world and is used when you need to create a class that implements an interface or extends a class just for a specific method's execution.
Local classes can access the outer class's members, as well as local variables of the method, provided those local variables are final or effectively final.
public class OuterClass {
public void processData() {
final int multiplier = 5;
class LocalHelper {
public int multiply(int value) {
return value * multiplier;
}
}
LocalHelper helper = new LocalHelper();
System.out.println(helper.multiply(10));
}
}
4. Anonymous Inner Classes
An anonymous inner class is a local inner class without a name. It is declared and instantiated in a single expression. They are typically used for implementing interfaces (like event listeners) or extending abstract classes on the fly.
public class Button {
public void setOnClickListener(ClickListener listener) {
// Implementation
}
}
// Usage:
Button btn = new Button();
btn.setOnClickListener(new ClickListener() {
@Override
public void onClick() {
System.out.println("Button clicked!");
}
});
Note: Since Java 8, single-abstract-method interfaces (Functional Interfaces) are usually implemented using Lambdas instead of anonymous inner classes.
Shadowing
If a declaration of a type (such as a member variable) in a nested class has the same name as a declaration in the enclosing scope, it shadows the declaration of the enclosing scope.
public class OuterClass {
public int x = 0;
class InnerClass {
public int x = 1;
void printValues(int x) {
System.out.println("Parameter x: " + x);
System.out.println("Inner x: " + this.x);
System.out.println("Outer x: " + OuterClass.this.x);
}
}
}
Why Use Nested Classes?
- Logical Grouping: If a class is useful to only one other class, it is logical to embed it in that class and keep the two together.
- Increased Encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them.
- More Readable Code: Nesting small classes within top-level classes places the code closer to where it is used.
Summary
- Static Nested Class: Like a regular class, but nested inside another. Doesn't need an outer instance.
- Member Inner Class: Bound to an outer class instance. Access to all outer members.
- Local Inner Class: Defined within a method/block.
- Anonymous Inner Class: Nameless local class, declared and instantiated simultaneously.