Mastering Java Nested and Inner Classes: Types, Examples, and Best Practices
Java Nested and Inner Classes
Discover how Java’s nested classes enhance encapsulation, improve readability, and enable powerful inner‑class patterns.
In Java you can declare a class inside another class—this is called a nested class. For instance:
class OuterClass {
// ...
class NestedClass {
// ...
}
}
There are two main flavors of nested classes:
- Non‑static nested class (commonly known as an inner class)
- Static nested class
Recommended reading:
- Java Access Modifiers
- Java Static Keyword
Non‑Static Nested Class (Inner Class)
An inner class resides within an outer class and can freely access the outer class’s members, even private ones. Because it is tied to an instance of the outer class, you must instantiate the outer class first.
Example 1: Inner Class
class CPU {
double price;
// inner class
class Processor{
double cores;
String manufacturer;
double getCache(){
return 4.3;
}
}
// protected inner class
protected class RAM{
double memory;
String manufacturer;
double getClockSpeed(){
return 5.5;
}
}
}
public class Main {
public static void main(String[] args) {
CPU cpu = new CPU();
CPU.Processor processor = cpu.new Processor();
CPU.RAM ram = cpu.new RAM();
System.out.println("Processor Cache = " + processor.getCache());
System.out.println("Ram Clock speed = " + ram.getClockSpeed());
}
}
Output:
Processor Cache = 4.3 Ram Clock speed = 5.5
Here, Processor and RAM are nested within CPU. The RAM class is declared protected, demonstrating that inner classes can use any Java access modifier.
In Main, we first instantiate the outer class CPU, then create inner‑class instances via the outer instance:
CPU.Processor processor = cpu.new Processor;
CPU.RAM ram = cpu.new RAM();
Tip: The dot (.) operator is used to bind an inner‑class instance to its outer instance.
Accessing Outer Class Members from an Inner Class
Inner classes can reference the outer class’s members through the this keyword prefixed with the outer class name, e.g., Car.this.carType. This syntax is necessary when the inner class has its own this context.
Example 2: Interacting with the Outer Class
class Car {
String carName;
String carType;
public Car(String name, String type) {
this.carName = name;
this.carType = type;
}
private String getCarName() {
return this.carName;
}
// inner class
class Engine {
String engineType;
void setEngine() {
if(Car.this.carType.equals("4WD")){
if(Car.this.getCarName().equals("Crysler")) {
this.engineType = "Smaller";
} else {
this.engineType = "Bigger";
}
} else {
this.engineType = "Bigger";
}
}
String getEngineType(){
return this.engineType;
}
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car("Mazda", "8WD");
Car.Engine engine = car1.new Engine();
engine.setEngine();
System.out.println("Engine Type for 8WD= " + engine.getEngineType());
Car car2 = new Car("Crysler", "4WD");
Car.Engine c2engine = car2.new Engine();
c2engine.setEngine();
System.out.println("Engine Type for 4WD = " + c2engine.getEngineType());
}
}
Output:
Engine Type for 8WD= Bigger Engine Type for 4WD = Smaller
Even though getCarName() is private, the inner class can invoke it because it resides within the same outer class.
Static Nested Class
A static nested class does not require an instance of the outer class to be created. Consequently, it cannot directly access non‑static members of the outer class. It is created using the outer class’s name:
OuterClass.NestedClass obj = new OuterClass.NestedClass();
Example 3: Static Nested Class
class MotherBoard {
static class USB{
int usb2 = 2;
int usb3 = 1;
int getTotalPorts(){
return usb2 + usb3;
}
}
}
public class Main {
public static void main(String[] args) {
MotherBoard.USB usb = new MotherBoard.USB();
System.out.println("Total Ports = " + usb.getTotalPorts());
}
}
Output:
Total Ports = 3
Example 4: Attempting to Access Outer Members in a Static Nested Class
class MotherBoard {
String model;
public MotherBoard(String model) {
this.model = model;
}
static class USB{
int usb2 = 2;
int usb3 = 1;
int getTotalPorts(){
if(MotherBoard.this.model.equals("MSI")) {
return 4;
} else {
return usb2 + usb3;
}
}
}
}
public class Main {
public static void main(String[] args) {
MotherBoard.USB usb = new MotherBoard.USB();
System.out.println("Total Ports = " + usb.getTotalPorts());
}
}
Running this code produces:
error: non-static variable this cannot be referenced from a static context
This error occurs because the static nested class cannot reference MotherBoard.this without an outer instance.
Key Takeaways
- Inner classes are treated as regular members of the outer class and can be declared
private,protected, orpublic. - They can freely access all outer class members, even those marked
private. - Static nested classes do not require an outer instance and cannot access non‑static outer members directly.
- Using nested classes promotes encapsulation and keeps related logic bundled together.
- Inner classes are ideal for callbacks, listeners, or helper objects tightly coupled to the outer class.
Java
- Java Classes and Objects: A Practical Guide
- Java Abstract Classes and Methods: A Comprehensive Guide
- Understanding Java Nested Static Classes: Usage, Differences, and Examples
- Mastering Java Anonymous Inner Classes: Definition, Syntax, and Practical Examples
- Mastering Java’s ObjectInputStream: A Comprehensive Guide
- Mastering Java ObjectOutputStream: Serialization, Methods, and Practical Examples
- Mastering Java’s PrintStream Class: Print, Println, and Printf Explained
- Master Java: Understanding Objects, Classes, and Core OOP Concepts
- Java Inner Classes Explained: Design, Syntax, and Practical Uses
- Java 9: Simplify Anonymous Inner Classes with the Diamond Operator