A non-static inner class (also known as a member inner class) is a nested class defined within another class without the static modifier.
The defining characteristic of a non-static inner class is that an instance of it is always implicitly associated with a specific instance of the outer class. It has direct access to all variables and methods of its outer class, including those marked as private.
When a class is useful only within the context of another class, nesting it logically groups them together. This keeps the codebase cleaner and prevents the package namespace from being cluttered with specialized, single-use classes.
If you have an object that represents a sub-component of a larger entity and needs to dynamically read or modify the parent entity's state, a non-static inner class is ideal.
BankAccount class has a nested Transaction class. Each transaction needs direct access to the specific account's private balance to update it.public class BankAccount {
private double balance;
private String accountNumber;
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
// Non-static inner class
public class Transaction {
private double amount;
public Transaction(double amount) {
this.amount = amount;
}
public void execute() {
// Directly accesses and modifies the outer class's private field
balance += amount;
System.out.println("Account " + accountNumber + " new balance: $" + balance);
}
}
}
Java's Collections Framework heavily relies on non-static inner classes to implement iterators. An iterator needs to traverse a collection, which requires direct access to the private data structures (like arrays or linked nodes) of the outer collection instance.
public class CustomList {
private Object[] elements;
// Returns an instance of the inner class
public Iterator iterator() {
return new ListIterator();
}
// Inner class implementing the Iterator interface
private class ListIterator implements Iterator {
private int currentIndex = 0;
@Override
public boolean hasNext() {
// Directly accesses elements array of the outer class instance
return currentIndex < elements.length;
}
@Override
public Object next() {
return elements[currentIndex++];
}
}
}
By making the non-static inner class private or protected, you can completely hide complex implementation details from the outside world. External classes can interact with the inner class only through interfaces publically exposed by the outer class.
// Syntax for instantiation:
BankAccount account = new BankAccount("12345", 1000.0);
BankAccount.Transaction transaction = account.new Transaction(250.0);