Java inner classes are classes that are defined within another class.
They provide a way to logically group classes that are only used in one place and help encapsulate the outer class functionality by hiding the inner class.
In Java, there are several types of inner classes:
Let’s go through each type with examples.
1. Non-static Inner Class (Member Inner Class)
A non-static inner class, also known as a member inner class, is a class defined inside another class without the static keyword. This type of inner class has access to the outer class’s instance variables and methods.
Example of a Non-static Inner Class
class OuterClass { private String message = "Hello from OuterClass"; // Inner class class InnerClass { public void displayMessage() { System.out.println("Message from OuterClass: " + message); } } public void createInner() { InnerClass inner = new InnerClass(); inner.displayMessage(); } } public class TestInnerClass { public static void main(String[] args) { OuterClass outer = new OuterClass(); outer.createInner(); // Alternatively, we can create an inner class instance directly OuterClass.InnerClass inner = outer.new InnerClass(); inner.displayMessage(); } }
Explanation
- The InnerClass is a non-static inner class, so it can access message, a private field in OuterClass.
- We can create an instance of InnerClass using the outer class instance (outer.new InnerClass()).
2. Static Nested Class
A static nested class is a static class inside an outer class. Since it’s static, it doesn’t have access to instance variables or methods of the outer class, but it can access static members.
Example of a Static Nested Class
class OuterClass { private static String staticMessage = "Hello from OuterClass"; // Static nested class static class StaticNestedClass { public void displayMessage() { System.out.println("Message from OuterClass: " + staticMessage); } } } public class TestStaticNestedClass { public static void main(String[] args) { // We can create an instance of the static nested class without an instance of the outer class OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass(); nested.displayMessage(); } }
Explanation
- StaticNestedClass is a static nested class. It doesn’t require an instance of OuterClass to be instantiated.
- StaticNestedClass can access staticMessage, a static field of OuterClass, but not instance fields.
3. Local Inner Class (Defined within a Method)
A local inner class is defined within a method of an outer class. It can only be accessed within that method and has access to the method’s final or effectively final variables.
Example of a Local Inner Class
class OuterClass { public void display(final String name) { // Local inner class class LocalInnerClass { public void printName() { System.out.println("Name: " + name); } } // Create an instance of the local inner class and call its method LocalInnerClass localInner = new LocalInnerClass(); localInner.printName(); } } public class TestLocalInnerClass { public static void main(String[] args) { OuterClass outer = new OuterClass(); outer.display("Alice"); } }
Explanation
- LocalInnerClass is defined inside the display method.
- It can access name, a parameter of display. In Java, the local variables must be effectively final to be accessed by a local inner class.
4. Anonymous Inner Class
An anonymous inner class is a class without a name that is defined and instantiated all in one place. It’s commonly used to provide implementations for interfaces or abstract classes on the fly.
Example of an Anonymous Inner Class Implementing an Interface
interface Greeting { void sayHello(); } public class TestAnonymousInnerClass { public static void main(String[] args) { // Create an anonymous inner class that implements Greeting Greeting greeting = new Greeting() { @Override public void sayHello() { System.out.println("Hello from an anonymous inner class!"); } }; greeting.sayHello(); } }
Explanation
- The anonymous inner class implements the Greeting interface without creating a separate class.
- The sayHello method is implemented on the spot, and we can call it directly.
Example of an Anonymous Inner Class Extending a Class
abstract class Animal { abstract void sound(); } public class TestAnonymousInnerClass { public static void main(String[] args) { // Create an anonymous inner class that extends Animal Animal dog = new Animal() { @Override public void sound() { System.out.println("Woof Woof"); } }; dog.sound(); } }
Explanation
- The anonymous inner class extends the Animal class and provides an implementation for the sound method directly where it is defined.
Summary
- Non-static Inner Class: A regular inner class with access to the outer class’s instance variables. Requires an outer class instance to instantiate.
- Static Nested Class: A static class inside another class. Doesn’t require an outer class instance and can only access static members.
- Local Inner Class: Defined inside a method and can access method variables that are final or effectively final.
- Anonymous Inner Class: A class with no name, defined and instantiated in one place, used mainly to provide implementations for interfaces or abstract classes.
Inner classes are useful for organizing code and implementing event listeners, callbacks, and other encapsulated logic specific to the outer class.