Member Inner Class
A member inner class is a non-static class declared directly inside another class — at the same level as fields and methods. It has a special privilege: it can freely access all members of its enclosing (outer) class, including private ones.
What Is a Member Inner Class?
When you define a class inside another class without the static keyword, you get a member inner class (sometimes just called an “inner class”). Think of it as a class that belongs to an instance of the outer class rather than to the outer class itself.
This relationship is what makes it powerful: every instance of the inner class holds an invisible reference to the outer instance that created it.
class Outer {
private int value = 42;
class Inner {
void display() {
// Inner can directly access outer's private field
System.out.println("Outer value: " + value);
}
}
}
Creating an Instance
Because a member inner class belongs to an outer instance, you must have an outer object first. There are two ways to instantiate it.
From outside the outer class:
public class Main {
public static void main(String[] args) {
Outer outer = new Outer(); // 1. create outer instance
Outer.Inner inner = outer.new Inner(); // 2. create inner via outer
inner.display();
}
}
Output:
Outer value: 42
From inside the outer class:
Inside the outer class, you can use new Inner() directly — no qualifier needed.
class Outer {
private int value = 42;
class Inner {
void display() {
System.out.println("Outer value: " + value);
}
}
void createInner() {
Inner inner = new Inner(); // no qualifier required here
inner.display();
}
}
Note: The syntax
outer.new Inner()looks unusual at first, but it is intentional — it creates anInnerinstance tied to the specificouterobject.
Accessing Outer Members
A member inner class can access every member of the enclosing class: public, protected, package-private, and private. This is the primary reason to use a member inner class over a standalone helper class.
class BankAccount {
private double balance = 1000.0;
private String owner = "Alice";
class Statement {
void print() {
// Accessing two private fields of BankAccount
System.out.println("Account owner : " + owner);
System.out.println("Current balance: $" + balance);
}
}
void printStatement() {
new Statement().print();
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
account.printStatement();
}
}
Output:
Account owner : Alice
Current balance: $1000.0
Shadowing and this Disambiguation
If the inner class declares a field or parameter with the same name as an outer field, the inner name shadows the outer one. Use the qualified OuterClass.this syntax to reach the outer version.
class Outer {
int x = 10;
class Inner {
int x = 20; // shadows Outer.x
void show() {
System.out.println("Inner x : " + x); // 20
System.out.println("Outer x : " + Outer.this.x); // 10
}
}
}
public class Main {
public static void main(String[] args) {
new Outer().new Inner().show();
}
}
Output:
Inner x : 20
Outer x : 10
See this Keyword for more on how this works in regular classes.
Inner Classes and Inheritance
A member inner class can extend another class or implement interfaces just like any regular class. It is often used to implement helper behavior that is tightly coupled to the outer class.
class Graph {
interface Drawable {
void draw();
}
class Node implements Drawable {
private String label;
Node(String label) {
this.label = label;
}
@Override
public void draw() {
System.out.println("Drawing node: " + label);
}
}
void render() {
Node node = new Node("A");
node.draw();
}
}
Tip: If your inner class does not need to access outer instance state, prefer a static nested class. It is lighter and avoids holding the outer reference.
Member Inner Class vs Static Nested Class
| Feature | Member Inner Class | Static Nested Class |
|---|---|---|
| Needs outer instance? | Yes | No |
| Access outer instance members? | Yes (including private) | No (only static members) |
| Holds implicit outer reference? | Yes | No |
| Risk of memory leak? | Yes (outer kept alive) | No |
| Typical use case | Tightly coupled helper | Loosely coupled helper / builder |
Read the static nested class page for a side-by-side comparison.
Under the Hood
When the Java compiler encounters a member inner class, it generates a separate top-level .class file named Outer$Inner.class. Inside that file the compiler inserts a hidden synthetic field — conventionally named this$0 — that stores a reference to the enclosing Outer instance.
// Roughly what the compiler produces for Inner
class Outer$Inner {
final Outer this$0; // synthetic reference injected by compiler
Outer$Inner(Outer outer) {
this.this$0 = outer;
}
void display() {
System.out.println("Outer value: " + this$0.value);
}
}
Because every Inner object holds a hard reference to its Outer object, the outer instance cannot be garbage-collected as long as any inner instance is reachable. In long-lived scenarios (listeners, callbacks stored in collections) this can cause subtle memory leaks — the outer object stays in the heap even after you think it is no longer needed.
You can inspect the generated bytecode with the javap tool:
javac Outer.java
javap -p Outer\$Inner
You will see the synthetic this$0 field in the output.
Warning: Storing an inner-class instance inside a static field, a singleton, or a long-lived collection keeps the entire outer object alive. If that is a problem, switch to a static nested class or extract the class to the top level.
Quick Rules to Remember
- A member inner class is declared inside a class body, without
static. - Instantiation always requires an outer instance:
outer.new Inner(). - It can access all outer members (any access level) directly.
- Use
OuterClass.this.fieldto disambiguate shadowed names. - The compiler creates
Outer$Inner.classwith a syntheticthis$0field. - Non-static inner classes can cause memory leaks — keep the relationship short-lived, or switch to a static nested class.
Related Topics
- Inner Classes — overview of all four kinds of nested classes in Java
- Static Nested Class — when you don’t need the outer reference
- Anonymous Inner Class — one-off implementations declared inline
- Local Inner Class — inner classes defined inside a method body
- Access Modifiers — understanding what
privateandprotectedmean across class boundaries - this Keyword — how
thisand qualifiedthiswork in Java