Classes in Java can have another class inside them, and they are known as nested classes. A nested class is a class inside another class called an enclosing class.
The scope of the nested class is until the scope of its enclosing class. That means a nested class cannot work independently of its enclosing class.
The nested class has access to all the data of the enclosing class, like methods, variables, and even private data. But the enclosing class cannot access any content of the nested class.
Java Inner Class
The inner class in Java means one class, which is a member of another class.
There are four types of inner classes in java.
1) Nested Inner class
2) Method Local inner classes
3) Anonymous inner classes
4) Static nested classes
See the following diagram of the Inner class in Java.
There are two types of nested classes: static and non-static nested classes.
Static nested classes have static keyword applied before the class keyword and cannot access the non-static data directly of its enclosing class, and it has to use the object of the enclosing class. That is why they are not used often.
A non-static nested class is called the inner class. This inner class has no restriction in accessing the data of its enclosing class.
Advantages of Java inner classes
There are three advantages of inner classes in java. They are as follows:
1) Nested classes represent a particular type of relationship that is it can access all the members (data members and methods) of an outer class, including private.
2) Nested classes are used to develop a more readable and maintainable code because it logically groups classes and interfaces in one place only.
3) Code Optimization: It requires less code to write.
Example
class Outer { class Inner { void innerMethod() { System.out.println("Called the Inner class method"); } } } class InnerDemo { public static void main(String[]args) { Outer.Inner InnerObj = new Outer().new Inner(); InnerObj.innerMethod(); } }
See the output.
In the above program, the Outer class contains the non-static nested class or the inner class names Inner. It has one method named innerMethod, which just prints “Called the Inner class Method.”
The main class InnerDemo, then makes the object of the Inner class.
Notice the syntax to make the Inner class object:
OuterClass.InnerClass ReferenceVariable = new OuterClass().new InnerClass();
As said earlier, the nested classes cannot work independently of the enclosing class. That’s why we use this syntax to make the object of the inner class.
The next program shows how an inner class can access the data of the outer class.
class Outer { int x=10; void displayInner() { Inner InnerObj = new Inner(); InnerObj.display(); } class Inner { void display() { System.out.println(x); } } } class AccessingOuterClassData{ public static void main(String[]args) { Outer out=new Outer(); out.displayInner(); } }
See the following output.
In this program, the variable x is accessed by the display method of the Inner class.
As already said, the inner class can access the data of the outer class, so this is a valid call.
Now, the display inner method of the Outer class is used to make the object of the Inner class and call the display method.
The main method object of the Outer class is made, and the display inner method is called. Now, let us see what happens when we try to access the data of the Inner class.
class Outer { class Inner { int x=10; } void displayInner() { System.out.println(x); } } class AccessingInnerClassData{ public static void main(String[]args) { Outer out=new Outer(); out.displayInner(); } }
See the output.
We get an error at line 10: we cannot find the symbol.
This proves that x is not accessible at line 10 because it is native to the Inner class, and that’s how inner classes provide encapsulation and abstraction.
Nested classes can also be created at any other block-like loops, methods, etc.
class InnerClassInLoop { public static void main(String[]args) { for(int x=0;x<5;x++) { class Inner { void show() { System.out.println("Inner"); } } Inner obj = new Inner(); obj.show(); } } }
See the output.
Here the for loop has the Inner class and its object, and the show method is called five times.
An inner class is a method of the enclosing class known as Method Local inner class.
Let’s see an example program of this.
class Outer { void outerMethod() { class Inner { void innerMethod() { System.out.println("Inside Inner Class"); } } Inner Obj = new Inner(); Obj.innerMethod(); } } class MethodLocalInnerClass { public static void main(String[]args) { Outer Obj = new Outer(); Obj.outerMethod(); } }
See the output.
The above program has a class named Inner, inside a method named outerMethod, which belongs to the Outer class. In the method, the reference variable of the Inner class is made, and a call to the method innerMethod is made.
The main method has the call to the outerMethod of the Outer class to execute the program.
Method local inner classes cannot have private, protected, static, and transient keywords before them.
Anonymous Inner Classes in Java
Anonymous classes as the name suggest, do not have names, and only one object can be created for them. If we want to make an anonymous inner class, there are two ways to extend a class or implement an interface.
Anonymous Inner class by extending a class is useful when we want to create a thread but do not want to create a class that extends the Thread class all the time.
class AnonymousInnerClassByExtendingClass { public static void main(String[]args) { Thread th = new Thread() { public void run() { System.out.println("Child Thread"); } }; th.start(); System.out.println("Main Thread"); } }
See the following output.
Here we are using the Anonymous Inner class by extending a class Thread Class.
Anonymous Inner class that implements an interface is useful when we want to make a thread by implementing the Runnable interface.
class AnonymousInnerClassByImplementingInterface { public static void main(String[]args) { Runnable r = new Runnable() { public void run() { System.out.println("Child Thread"); } }; Thread t = new Thread(r); t.start(); System.out.println("Main Thread"); } }
See the following output.
Here we are using the Anonymous Inner class that implements the Runnable Interface.
In both programs, we can observe that there is no named class that is used to make threads, and despite that, threads are created. This is the power of the Anonymous Inner class. It saves time and lines of code.
Static Nested Class
A static inner class is the nested class, the static member of the outer class. It can be accessed without instantiating the outer class, using other static members.
Like the static members, the static nested class does not have access to the instance variables and methods of the outer class.
The syntax of a static nested class is as follows.
class MyOuter { static class Nested_Demo { } }
Instantiating a static nested class differs from instantiating the inner class. See the following program shows how to use a static nested class.
See the following code example.
public class Outer { static class Nested_Demo { public void my_method() { System.out.println("This is nested class"); } } public static void main(String args[]) { Outer.Nested_Demo nested = new Outer.Nested_Demo(); nested.my_method(); } }
See the output.
This is my nested class
That’s it.