Static and Non-static inner classes in Java
In Java, non-static inner classes have an implicit reference to the enclosing instance of the outer class. This means that they have access to the instance variables and methods of the outer class, and can be used to create multiple instances of the inner class that are associated with different instances of the outer class.
For example, consider the following code:
class Outer {
private int x;
class Inner {
public void printX() {
System.out.println(x);
}
}
}
Outer outer1 = new Outer();
outer1.x = 5;
Outer.Inner inner1 = outer1.new Inner();
inner1.printX(); // prints 5
Outer outer2 = new Outer();
outer2.x = 10;
Outer.Inner inner2 = outer2.new Inner();
inner2.printX(); // prints 10
Here, the Outer
class has an inner class Inner
, which has a method printX
that prints the value of x
from the enclosing Outer
instance. The code creates two instances of Outer
(outer1
and outer2
) and two instances of Inner
(inner1
and inner2
), each of which is associated with a different instance of Outer
. When printX
is called on inner1
and inner2
, it prints the value of x
from the corresponding Outer
instance.
Because non-static inner classes have an implicit reference to the enclosing instance, they require additional memory to store this reference. This means that they are slightly less memory-efficient than static inner classes, which don’t have an implicit reference to the enclosing instance and don’t require additional memory for this purpose.
On the other hand, static inner classes can’t access the instance variables or methods of the outer class, so they are more limited in what they can do. They are useful when you want to define a class that is closely related to the outer class and doesn’t need to access its instance variables or methods.
Non-static inner classes (also known as inner classes or inner objects) are useful when you want to define a class that is closely related to another class, and has access to the instance variables and methods of the outer class.
Non- Static inner classes Usages
Here are a few situations where you might want to use a non-static inner class:
- When the inner class needs to access instance variables or methods of the outer class that are not
static
. Because non-static inner classes have an implicit reference to the enclosing instance of the outer class, they can access non-static instance variables and methods directly. - When you want to define multiple instances of the inner class that are associated with different instances of the outer class. For example, you might want to create a non-static inner class
Button
for aDialog
class, where eachButton
instance is associated with a differentDialog
instance and can access the instance variables and methods of theDialog
instance.
When you want to define a class that is only used within the context of the outer class and is not intended to be used independently. Non-static inner classes can only be accessed from within the outer class, so they are more encapsulated and less prone to being used in unintended ways.
Static inner classes Usages
We can use static inner classes when we don't need to access any instance variables or methods of the outer class, so there is no need for them to have an implicit reference to an enclosing instance of the outer class. This makes them more memory-efficient than non-static inner classes, which do have an implicit reference to the enclosing instance.
Let’s say we need to design graphs and it contains Nodes and edges. The Node
and Edge
classes are closely related to the Graph
class and are only used within the context of a Graph
object. Defining them as static inner classes makes it clear that they are part of the Graph
class and are not intended to be used independently.
public class Graph {
Map <String, Node> nodeMap;
public Graph () {
nodeMap = new HashMap<>();
}
static class Node {
String name;
List <Edge> edgeList;
public Node(String name) {
this.name = name;
edgeList = new ArrayList();
}
}
static class Edge {
Node source;
Node Destination;
String type;
public Edge(Node source, Node destination, String type) {
this.Destination = destination;
this.source = source;
this.type = type;
}
}
}
Static inner classes cannot access the instance variables or methods
Here is an example that illustrates the fact that static inner classes cannot access the instance variables or methods of the outer class:
class Outer {
private int x;
static class Inner {
public void printX() {
System.out.println(x); // compilation error: cannot access x
}
}
}
In this example, the Outer
class has a private instance variable x
and a static inner class Inner
. The Inner
class has a method printX
that tries to access the value of x
from the enclosing Outer
instance. However, this code will not compile, because static inner classes cannot access instance variables or methods of the outer class.
To access the instance variables or methods of the outer class from a static inner class, you can either:
- Make the instance variables or methods
static
as well. This allows the inner class to access them using the outer class name (e.g.Outer.x
). - Pass an instance of the outer class to the inner class and store it in a field. The inner class can then access the instance variables or methods of the outer class through this field.
Here is an example that shows how to do this:
class Outer {
private int x;
public void setX(int x) {
this.x = x;
}
static class Inner {
Outer outer;
public Inner(Outer outer) {
this.outer = outer;
}
public void printX() {
System.out.println(outer.x);
}
}
}
Outer outer = new Outer();
outer.setX(5);
Outer.Inner inner = new Outer.Inner(outer);
inner.printX(); // prints 5
In this example, the Outer
class has a non-static method setX
that sets the value of x
, and a static inner class Inner
that has a field outer
of type Outer
. The Inner
class has a constructor that takes an Outer
instance and stores it in the outer
field. The printX
method of the Inner
class can then access the x
field of the outer
instance using the outer.x
notation.