Java > Object-Oriented Programming (OOP) > Nested and Inner Classes > Non-static Inner Classes
Non-Static Inner Class Example: Car and Engine
This example demonstrates a non-static inner class (Engine) within an outer class (Car). Non-static inner classes have access to the outer class's members (both private and public). This allows for a strong relationship between the inner and outer classes, where the inner class's functionality is closely tied to the outer class.
Code Demonstration
The `Car` class has `model` and `color` attributes. The `Engine` class is a non-static inner class. It has access to the `model` and `color` attributes of the `Car` class using `Car.this`. The `main` method demonstrates how to create an instance of the `Engine` class associated with a specific `Car` instance. Notice the syntax: `Car.Engine myEngine = myCar.new Engine(203);`. You must have an instance of the outer class (`myCar`) before you can create an instance of the inner class.
public class Car {
private String model;
private String color;
public Car(String model, String color) {
this.model = model;
this.color = color;
}
public String getModel() {
return model;
}
public String getColor() {
return color;
}
// Non-static Inner Class (Engine)
public class Engine {
private int horsepower;
public Engine(int horsepower) {
this.horsepower = horsepower;
}
public int getHorsepower() {
return horsepower;
}
// Accessing outer class members
public String getCarDetails() {
return "Car Model: " + Car.this.model + ", Color: " + Car.this.color + ", Engine Horsepower: " + horsepower;
}
}
public static void main(String[] args) {
Car myCar = new Car("Toyota Camry", "Silver");
// Creating an Engine instance associated with myCar
Car.Engine myEngine = myCar.new Engine(203);
System.out.println(myEngine.getCarDetails());
}
}
Concepts Behind the Snippet
Non-static inner classes are closely tied to their outer class instances. They can access all members of the outer class, even private ones. Each instance of a non-static inner class holds a reference to the outer class instance that created it. This is different from static nested classes, which do not require an outer class instance and cannot access instance members of the outer class.
Real-Life Use Case
Consider a GUI application. You might have a `Window` class and an `EventHandler` inner class that handles user input. The `EventHandler` needs to access the `Window`'s components (e.g., buttons, text fields) to update them in response to events. A non-static inner class makes this easy because it has direct access to the `Window`'s members.
//Illustrative Example
class Window {
private Button closeButton;
private TextField inputField;
class EventHandler {
public void onClickClose() {
closeButton.setVisible(false); //Can access outer class members
}
public String getInputText(){
return inputField.getText();
}
}
}
Best Practices
Use non-static inner classes when the inner class's functionality is strongly dependent on the outer class and needs to access its members. Keep inner classes small and focused on a specific task. Avoid creating deeply nested inner classes, as they can become difficult to understand and maintain.
// Example of good inner class usage:
class OuterClass {
private int outerData;
class InnerClass {
public void doSomething() {
// Operate on outerData
}
}
}
// Example of potentially bad inner class usage (too complex):
class OuterClass {
class InnerClass {
class DeeperInnerClass {
// Too much nesting; consider refactoring
}
}
}
Interview Tip
Be prepared to explain the difference between static and non-static inner classes. Emphasize that non-static inner classes have access to the outer class's instance members, while static nested classes do not. Also, be ready to discuss when you would choose one over the other. Explain when the relation is very strong and the inner class cannot exist without the outer class.
When to Use Them
Use non-static inner classes when you need to tightly couple the inner class's behavior to the outer class's state and methods. This is useful when the inner class logically represents a component or aspect of the outer class. For instance: event handlers, iterators, and helper classes specific to a data structure.
Memory Footprint
Each instance of a non-static inner class holds a hidden reference to the outer class instance that created it. This means that inner class instances will contribute to the overall memory footprint of the application, especially if many instances are created. Be mindful of the number of inner class instances you create, particularly within long-lived outer class instances.
Alternatives
If the inner class does not need to access the outer class's instance members, consider using a static nested class. Alternatively, you can extract the inner class into a separate top-level class and pass necessary data as arguments to its methods. Use composition to achieve the same goal. For instance, you can pass an Engine instance in the constructor of the Car.
//Alternative using composition
class Engine{
private int horsepower;
public Engine(int horsepower){
this.horsepower = horsepower;
}
public int getHorsepower() {
return horsepower;
}
}
class Car{
private Engine engine;
public Car(Engine engine){
this.engine = engine;
}
public int getEngineHorsepower(){
return engine.getHorsepower();
}
}
Pros
Cons
FAQ
-
What is the difference between a static nested class and a non-static inner class?
A static nested class does not require an instance of the outer class and cannot access the outer class's instance members directly. A non-static inner class requires an instance of the outer class and has access to all of the outer class's members, including private ones. -
How do I create an instance of a non-static inner class?
You must first create an instance of the outer class. Then, use that instance to create an instance of the inner class using the `outerObject.new InnerClass()` syntax. -
Can a non-static inner class access private members of the outer class?
Yes, a non-static inner class can access all members of the outer class, including private ones.