As you know, there are inner classes that you create inside outer classes. But have you wondered if there are any other ways to create a new class inside the other? Today you will meet the different two types of nested classes. Our lovely heroes are called static nested class and local inner class. What's more, after completing this topic, you'll have the whole picture of the hierarchy of nested classes.
Types of nested classes
As you remember, a class is called nested when it's declared within another class. Let's look into the types of nested classes. There are four types of nested classes.
You can find the hierarchy in the picture, where the blue ones are these types.
First, all nested classes are divided into static and non-static ones. As you can see, only one type has the static keyword.
In the Java documentation, you also may see that the non-static group includes local inner classes and anonymous inner classes along with the inner classes you know about.
Let's now take a closer look at static nested classes and local inner classes.
Static nested class
Imagine, that one day you woke up and decided to draw. Obviously, you would do so with the help of some Java code. Your ultimate goal is to draw a painting. But how to create a masterpiece? That'll require doing some sketches first.
How would you organize your code? It's a good idea to use a nested class here. But if you choose to employ an inner class then a Sketch would only exist if the Painting was instantiated previously. So, we'd prefer something different. And the static nested class is going to help us.
It allows us to create a Sketch first, and then, only if you're ready to become an author of a masterpiece, you can create a Painting.
public class Painting {
private String name;
public static class Sketch {
private int id;
public Sketch(int id) {
this.id = id;
}
public void drawSketch() {
drawForest();
drawBear();
}
private void drawForest() {
System.out.println("Forest was drawn in a sketch!");
}
}
private void drawBear() {
System.out.println("Bear was drawn in a sketch!");
}
}
}
Let's try it:
public class Main {
public static void main(String[] args) {
Painting.Sketch sketch = new Painting.Sketch(0);
sketch.drawSketch();
}
}
Greetings to our bear in a forest!
Forest was drawn in a sketch!
Bear was drawn in a sketch!Scope of a static nested class
Let's modify our example a little bit with Sketch and Painting and talk about their scope.
public class Painting {
private String name;
private static double length;
private static double width;
public static void setLength(double length) {
Painting.length = length;
}
public static void setWidth(double width) {
Painting.width = width;
}
public static class Sketch {
private int id;
public Sketch(int id) {
this.id = id;
}
public void drawSketch() {
drawForest();
drawBear();
}
private void drawForest() {
if (Painting.length > 5 && Painting.width > 3) {
System.out.println("Big forest was drawn in a sketch!");
} else {
System.out.println("Small forest was drawn in a sketch!");
}
}
private void drawBear() {
System.out.println("Bear was drawn in a sketch!");
}
}
}
We've added two static fields to the Painting class, namely length and width. And we've also added a condition to the method drawForest of the class Sketch.
With setters, we decide what sizes our Painting will be and then use that information inside the method drawForest.
public class Main {
public static void main(String[] args) {
Painting.setLength(10);
Painting.setWidth(7);
Painting.Sketch sketch = new Painting.Sketch(1);
sketch.drawSketch();
}
}
And here is a big forest with a bear:
Big forest was drawn in a sketch!
Bear was drawn in a sketch!
So, we've got access to private static fields from a static nested class!
And is there anything that we can't see? Yes, instance variables and methods of an outer class, including the field name in our example.
From the outside everything works as usual: we create an instance of a static nested class and good luck! Just mind the syntax:
OuterClass.NestedClass nested = new OuterClass.NestedClass();
Remember about access modifiers: if you make a static nested class private, then it can only be accessed inside the outer class. The same works with fields and methods.
Local inner class
In real life, you won't face local inner classes often, but it is worth knowing how to use them if you want to be a proper programmer.
You can define a local inner class inside any block. But, usually, local inner classes are defined inside a method body.
Let's move to an example now:
public class Outer {
private int number = 10;
void someMethod() {
class LocalInner {
private void print() {
System.out.println("number = " + Outer.this.number);
}
}
LocalInner inner = new LocalInner();
inner.print();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.someMethod();
}
}
Here we have an outer class Outer and a method someMethod in it. We define our local inner class inside someMethod and we also create an instance of LocalInner there.
Have you noticed that our class LocalInner doesn't have an access modifier? And it can't!
There are other restrictions. Inside a local inner class you cannot define any static members, enums or interfaces.
Scope of a Local Inner class
The scope of the local inner class is restricted to its containing block, which is someMethod in our example.
public class Outer {
private int number = 10;
void someMethod() {
final int x = 5;
class Inner {
private void print() {
System.out.println("x = " + x);
System.out.println("number = " + Outer.this.number);
}
}
Inner inner = new Inner();
inner.print();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.someMethod();
}
}
What can we see inside the local inner class? Members of the outer class, including the field number. And local variables of the enclosing block, such as void someMethod. Local variables must be declared as final or be effectively final, the latter means their value is never changed after initialization and there's no need for the keyword final.
Remember, a local inner class can be instantiated only within the block where the inner class is defined.
So other parts of the code don't know that it exists.
Summary
If you want something close to a nested class, but don't want to instantiate an outer class — a static nested class is always there for you!
Static nested classes add functionality to an outer class and may be used for different purposes: usually, as a special structure that is connected with the outer class.
And have you heard about a class in a block? Yeah, you are a good student and you know, that it is called a local inner class and its scope is restricted within a block.
Finally, nested classes organize code and help your package be more reasonable, increase encapsulation, since you can hide some code in a nested class, and the last point is that small classes may provide more readable code.