In Java some classes can contain other classes within them. Such classes are called nested classes. Classes defined within other classes generally fall into two categories — static and non-static. Nested non-static classes are called inner. Nested classes that are declared static are called static nested classes.
In fact, there is nothing complicated here, although the terminology looks somewhat fuzzy and can sometimes confuse even a professional software developer.
Nested and inner classes
So all classes located inside other classes are called Nested classes.
class OuterClass {
...
class NestedClass {
...
}
}
Nested Classes that are not static are called Inner Classes, and those that are static are called static Nested Classes.
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Thus, all Inner Classes are Nested, but not all Nested are Inner. These are the main definitions. Inner classes are a kind of security mechanism in Java. We know that an ordinary class cannot be associated with a private access modifier. However, if our class is a member of another class, then the inner class can be made private. This feature is also used to access private class members.
Inner Class Example
So, let's try to create some class, and inside it — another class. Imagine some kind of modular game console. There is a “box” itself, and certain modules can be connected to it. For example, a game controller, a steering wheel, a VR helmet, which, as a rule, do not work without the console itself. Here we have the GameConsole class. It has 2 fields and 1 method — start(). The difference between GameCosole and the class we are used to is that it has an internal GameController class.
public class GameConsole {
private String model;
private int weight;
public void run() {
System.out.println("Game console is on");
}
public class GameController {
private String color;
public void start() {
System.out.println("start button is pressed");
}
public void x() {
System.out.println("x button is pressed");
}
public void y() {
System.out.println("y button is pressed");
}
public void a() {
System.out.println("a button is pressed");
}
public void b() {
System.out.println("b button is pressed");
}
public void mover() {
System.out.println("mover button is pressed");
}
}
}
At this point, you might be wondering: why not make these classes "separate"? It is not necessary to make them nested. Indeed it is possible. Rather, it is about the correct design of classes in terms of their use. Inner classes are created to highlight in the program an entity that is inextricably linked with another entity.
A controller or, for example, a VR helmet are components of the console. Yes, they can be bought separately from the console, but cannot be used without it.
If we made all these classes separate public classes, our program could have, for example, the following code:
public class Main {
public static void main(String[] args) {
GameController controller = new GameController();
controller.x();
}
}
What happens in this case isn’t clear, since the controller itself does not work without a console.
We have created a game console object. We created its sub-object — the game controller. And now we can play, just press the right keys. The methods we need are called on the right objects. Everything is simple and convenient.
In this example, extracting the game controller enhances the encapsulation (we hide the details of the console parts inside the corresponding class), and allows for a more detailed abstraction.
But if we, for example, create a program that simulates a store where you can separately buy a VR helmet or controller, this example will fail. There it is better to create a game controller separately.
Let's take another example. We mentioned above that we can make the inner class private and still call it from the outer class. Below is an example of such classes.
class OuterClass {
// inner class
private class InnerClass {
public void print() {
System.out.println("We are in the inner class...");
}
}
// method of outer class. We are create an inner class from the method of outer one
void display() {
InnerClass inner = new InnerClass();
inner.print();
}
}
Here the OuterClass is the outer class, InnerClass is the inner class, display() is the method inside which we are creating an object of the inner class.
Now let’s write a demo class with a main method where we are going to invoke the display() method.
public class OuterDemoMain {
public static void main(String args[]) {
// create an object of the outer class
OuterDemo outer = new OuterDemo();
outer.display();
}
}
If you run this program, you will get the following result:
We are in the inner class...
Inner classes classification
The inner classes themselves or nested non-static classes fall into three groups.- Inner class as is. Just one non-static class inside the other one as we demonstrated above with GameConsole and GameController example.
- Method-local Inner class is a class inside a method.
- Anonymous Inner class.
Method local Inner class
In Java you can write a class inside a method and it’s a local type. Like local variables, the scope of an inner class is limited within a method. A method-local inner class can only be created within the method where the inner class is defined. Let's demonstrate how to use the local method inner class.
public class OuterDemo2 {
//instance method of the outer class OuterDemo2
void myMethod() {
String str = "and it's a value from OuterDemo2 class' myMethod ";
// method-local inner class
class methodInnerDemo {
public void print() {
System.out.println("Here we've got a method inner class... " );
System.out.println(str);
}
}
// Access to the inner class
methodInnerDemo inn = new methodInnerDemo();
inn.print();
}
}
Now we are going to write a demo class with a main method where we are going to invoke the outer() method.
public class OuterDemoMain {
public static void main(String args[]) {
OuterDemo2 outer = new OuterDemo2();
outer.myMethod();
}
}
The output is:
Here we've got a method inner class...
and it's a value from OuterDemo2 class' myMethod
Anonymous inner class
An inner class declared without a class name is called an anonymous inner class. When we declare an anonymous inner class, we immediately instantiate it. Typically, such classes are used whenever you need to override a class or interface method.
abstract class OuterDemo3 {
public abstract void method();
}
class outerClass {
public static void main(String args[]) {
OuterDemo3 inner = new OuterDemo3() {
public void method() {
System.out.println("Here we've got an example of an anonymous inner class");
}
};
inner.method();
}
}
The output is here:
Here we've got an example of an anonymous inner class...
Anonymous Inner Class as Argument
You can also pass an anonymous inner class as an argument to the method. Here is an example.
interface OuterDemo4 {
String hello();
}
class NewClass {
// accepts the object of interface
public void displayMessage(OuterDemo4 myMessage) {
System.out.println(myMessage.hello());
System.out.println("example of anonymous inner class as an argument");
}
public static void main(String args[]) {
NewClass newClass = new NewClass();
//here we pass an anonymous inner class as an argument
newClass.displayMessage(new OuterDemo4() {
public String hello() {
return "Hello!";
}
});
}
}
The output is here:
Hello!
example of anonymous inner class as an argument
To reinforce what you learned, we suggest you watch a video lesson from our Java Course
GO TO FULL VERSION