Skip to main content
Advertisement

6.5 Inner Classes

Defining a class inside another class is called an inner class. It is used to logically group code that is closely related to a specific class and unnecessary for the outside world.

Types of Inner Classes

TypeDeclaration LocationCharacteristics
Member Inner ClassAs a class memberCan access all members of the outer class
Static Nested ClassWith static keywordCan only access static members of the outer class
Local Inner ClassInside a methodOnly usable within that method
Anonymous Inner ClassClass declaration and instantiation at onceFor one-time implementations

1. Member Inner Class

The most common form. Can access all members of the outer class (including private).

public class Outer {
private String outerField = "Outer class field";

class Inner {
void display() {
System.out.println("Accessing from inner: " + outerField);
}
}
}

// Usage: must create outer class object first
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display(); // Accessing from inner: Outer class field

2. Static Nested Class

A static inner class. Can be used without an outer class instance. Can only access static members of the outer class.

public class Database {
private static String url = "jdbc:mysql://localhost";

// Static nested class: commonly used in Builder pattern
static class Builder {
private String host = "localhost";
private int port = 3306;
private String dbName;

Builder host(String host) { this.host = host; return this; }
Builder port(int port) { this.port = port; return this; }
Builder dbName(String db) { this.dbName = db; return this; }

Database build() { return new Database(host, port, dbName); }
}

private Database(String host, int port, String dbName) {
System.out.printf("Connecting: %s:%d/%s%n", host, port, dbName);
}
}

// Usage: no outer class object needed
Database db = new Database.Builder()
.host("myserver.com")
.port(5432)
.dbName("shop")
.build();

3. Local Inner Class

Declared inside a method and only usable within that method. Rarely used; mostly replaced by lambda expressions.

public class LocalInnerExample {
void doSomething() {
final int localVar = 100; // must be effectively final

class LocalHelper {
void help() {
System.out.println("Using local var: " + localVar);
}
}

new LocalHelper().help(); // Using local var: 100
}
}

4. Anonymous Inner Class

A class with no name, instantiated at the point of declaration. Used for one-time implementations of interfaces or abstract classes. Mostly replaced by lambda expressions since Java 8.

interface Greeting {
void greet(String name);
}

// Anonymous inner class (pre-Java 8 style)
Greeting formal = new Greeting() {
@Override
public void greet(String name) {
System.out.println("Good day, " + name + ".");
}
};

// Lambda expression (Java 8+ recommended)
Greeting casual = name -> System.out.println("Hey, " + name + "!");

formal.greet("Alice"); // Good day, Alice.
casual.greet("Bob"); // Hey, Bob!

Pro Tip

Inner class selection guide:

  • Member inner class: When strongly dependent on outer instance state (e.g., custom iterator implementations)
  • Static nested class: Builder pattern, helper classes logically tied to the outer class → Most commonly used
  • Anonymous inner class: Interfaces not supported by lambdas (more than one abstract method) or legacy code
  • Lambda expression: Always prefer lambdas for functional interfaces (single abstract method)

Memory warning: Member inner class instances implicitly hold a reference to the outer class instance. This can cause memory leaks. When the outer instance is not needed, always choose static nested class.

Advertisement