Nested Classes in Java
In Java, you can define a class within another class. Such a class is called a nested class. Nested classes allow you to logically group classes that are only used in one place, which increases the use of encapsulation and creates more readable and maintainable code.
There are four types of nested classes:
- Static Nested Class: A
staticclass defined within another class. - Inner Class (or Non-static Nested Class): A non-
staticclass defined within another class. - Local Class: A class defined inside a method body.
- Anonymous Class: A class without a name, defined and instantiated at the same time.
1. Static Nested Class
A nested class declared as static behaves much like a regular top-level class but is namespaced within its enclosing class.
- Cannot access instance (non-static) members of the enclosing class directly. It can only access
staticmembers. - It is accessed using the enclosing class name:
OuterClass.StaticNestedClass. - You do not need an instance of the outer class to create an instance of a static nested class.
Example:
public class OuterClass {
static int outerStaticVar = 10;
int outerInstanceVar = 20;
// Static nested class
static class StaticNestedClass {
void display() {
// Works: Can access static members of the outer class
System.out.println("Accessing static variable: " + outerStaticVar);
// COMPILE ERROR! Cannot access instance members
// System.out.println(outerInstanceVar);
}
}
}
// How to instantiate and use it:
public class Test {
public static void main(String[] args) {
OuterClass.StaticNestedClass nestedObj = new OuterClass.StaticNestedClass();
nestedObj.display(); // Prints "Accessing static variable: 10"
}
}
2. Inner Class (Non-Static)
An inner class is associated with an instance of the enclosing class.
- Can access all members (static and instance) of the enclosing class, including
privateones. - It requires an instance of the outer class to be created. Each instance of an inner class is implicitly linked to an instance of the outer class.
Example:
public class OuterClass {
private int outerInstanceVar = 20;
// Inner class
class InnerClass {
void display() {
// Works: Can access instance members of the outer class
System.out.println("Value from outer instance: " + outerInstanceVar);
}
}
}
// How to instantiate and use it:
public class Test {
public static void main(String[] args) {
OuterClass outerObj = new OuterClass();
OuterClass.InnerClass innerObj = outerObj.new InnerClass(); // Note the syntax
innerObj.display(); // Prints "Value from outer instance: 20"
}
}
3. Local Class
A local class is a class that is defined inside a method body.
- The scope of the class is limited to the method where it is defined.
- It can access the members of the enclosing class, just like an inner class.
- It can also access local variables of the method, but only if they are
finalor effectively final.
Example:
public class LocalClassExample {
public void aMethod() {
final String message = "Hello from the method!";
// This is a local class
class Inner {
public void aMethodInInner() {
System.out.println(message); // Accessing local variable
}
}
// You can only instantiate it within this method
Inner inner = new Inner();
inner.aMethodInInner();
}
public static void main(String[] args) {
LocalClassExample outer = new LocalClassExample();
outer.aMethod(); // Prints "Hello from the method!"
}
}
4. Anonymous Class
An anonymous class is a class without a name. It allows you to declare and instantiate a class at the same time. It's a concise way to create a one-time-use class.
- They are typically used to create an instance of an object with an "on the fly" implementation of an interface or an abstract class.
- They are heavily used in GUI applications (like Android or Swing) for event listeners.
Example: Implementing an Interface
Let's say we have an interface EventListener.
interface EventListener {
void onClick();
}
public class AnonymousClassDemo {
public void clickButton() {
// Here, we declare and instantiate an unnamed class that
// implements the EventListener interface, all in one step.
EventListener listener = new EventListener() {
@Override
public void onClick() {
System.out.println("You successfully clicked a button!");
}
};
listener.onClick();
}
public static void main(String[] args) {
AnonymousClassDemo demo = new AnonymousClassDemo();
demo.clickButton();
}
}
Without an anonymous class, you would have to create a separate, named class (e.g., MyListener) that implements the interface, which adds more boilerplate code for a single use.
If the interface is a functional interface (has only one abstract method), you can use a lambda expression for even more concise code.
// Using a lambda expression instead of an anonymous class
EventListener listener = () -> System.out.println("Clicked with a lambda!");
listener.onClick();