Member Inner Class in Java – Syntax, Rules and Examples
A member inner class is a non-static class declared directly inside another class, at the same level as fields and methods. Every inner class object is bound to an object of the outer class and can freely use that outer object's fields and methods, including private ones.
This tutorial shows how to declare and instantiate member inner classes, how they access the outer object, how to resolve name clashes with Outer.this, what the compiler generates behind the scenes, and when a static nested class is the better choice.
1. Syntax
class Outer {
[access modifier] class Inner { // no 'static' keyword
// fields, constructors, methods
}
}
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // inner object bound to 'outer'
Like other members, an inner class can be public, protected, package-private or private, and can also be final or abstract.
2. Example: Students of a University
public class MemberInnerBasics {
static class University {
private final String name;
private int enrolled = 0;
University(String name) { this.name = name; }
// Member inner class: each Student belongs to one University object
class Student {
private final String studentName;
private final int rollNo;
Student(String studentName) {
this.studentName = studentName;
this.rollNo = ++enrolled; // updates the OUTER object's field
}
String card() { return studentName + " | roll " + rollNo + " | " + name; }
}
Student admit(String who) { return new Student(who); } // inside: plain 'new'
}
public static void main(String[] args) {
University iit = new University("IIT Delhi");
University nit = new University("NIT Trichy");
University.Student a = iit.new Student("Asha"); // outside: outer.new Inner()
University.Student r = iit.admit("Ravi");
University.Student m = nit.new Student("Meera");
System.out.println(a.card());
System.out.println(r.card());
System.out.println(m.card());
}
}
Asha | roll 1 | IIT Delhi Ravi | roll 2 | IIT Delhi Meera | roll 1 | NIT Trichy
- Each
Studentreads its university'snameand increments itsenrolledcounter directly. - Students of different universities see different outer objects, so roll numbers restart for NIT.
- Outside the outer class, write
outerObject.new Inner(); inside an instance method, plainnew Inner()usesthisas the outer object.
3. A Classic Use: Iterators
The JDK's collections implement iterators as inner classes, because an iterator needs direct access to its collection's internal data. A private inner class keeps the implementation hidden:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class IteratorExample {
// Classic use: an iterator is an inner class that walks the outer object's data
static class Playlist implements Iterable<String> {
private final String[] songs;
Playlist(String... songs) { this.songs = songs; }
@Override public Iterator<String> iterator() { return new SongIterator(); }
private class SongIterator implements Iterator<String> { // private: hidden from users
private int index = 0;
public boolean hasNext() { return index < songs.length; } // reads outer's array
public String next() {
if (!hasNext()) throw new NoSuchElementException();
return songs[index++];
}
}
}
public static void main(String[] args) {
Playlist p = new Playlist("Kesariya", "Tum Hi Ho", "Naatu Naatu");
for (String song : p) System.out.println("Playing: " + song);
}
}
Playing: Kesariya Playing: Tum Hi Ho Playing: Naatu Naatu
4. Name Clashes and Outer.this
When the inner class, the outer class and a parameter use the same name, this refers to the inner object and OuterClassName.this to the enclosing object:
public class ShadowingOuterThis {
private int value = 10;
class Inner {
private int value = 20;
void show(int value) {
System.out.println("parameter value: " + value);
System.out.println("this.value (inner): " + this.value);
System.out.println("Outer.this.value: " + ShadowingOuterThis.this.value);
}
}
public static void main(String[] args) {
new ShadowingOuterThis().new Inner().show(30);
}
}
parameter value: 30 this.value (inner): 20 Outer.this.value: 10
5. What the Compiler Generates
An inner class compiles to a separate file, Outer$Inner.class. The compiler adds a hidden final field (this$0) holding the outer object, and an extra constructor parameter to pass it in:
$ javap -p "MemberInnerBasics$University$Student"
Compiled from "MemberInnerBasics.java"
class MemberInnerBasics$University$Student {
private final java.lang.String studentName;
private final int rollNo;
final MemberInnerBasics$University this$0;
MemberInnerBasics$University$Student(MemberInnerBasics$University, java.lang.String);
java.lang.String card();
}
That hidden reference is how inner code reaches outer fields, and it is also why an inner object keeps its outer object alive in memory.
6. Static Members in Inner Classes (Java 16+)
Before Java 16, inner classes could not declare static members other than compile-time constants. Since Java 16 (with records), they can:
public class InnerStaticJava16 {
class Inner {
static int instances = 0; // allowed since Java 16
static String describe() { return "static method in an inner class"; }
Inner() { instances++; }
}
public static void main(String[] args) {
InnerStaticJava16 outer = new InnerStaticJava16();
outer.new Inner();
outer.new Inner();
System.out.println(Inner.describe() + ", instances = " + Inner.instances);
}
}
static method in an inner class, instances = 2
7. Member Inner Class vs Static Nested Class
| Aspect | Member inner class | Static nested class |
|---|---|---|
| Declared with | No static | static |
| Outer instance | Required; reference stored in each object | Not needed |
| Access to outer instance members | Direct | Only through an explicit reference |
| Creation from outside | outer.new Inner() | new Outer.Nested() |
| Memory | Extra reference; may keep outer object alive | No hidden reference |
Use a member inner class only when the inner object genuinely needs its outer object. Otherwise, make it static. See Static Nested Class.
8. Summary
- A member inner class is a non-static class declared as a member of another class.
- Each instance is bound to an outer instance and can use its members, including private ones.
- Create it with
outer.new Inner(); refer to the outer object withOuter.this. - The compiler stores the outer reference in a hidden field, which can cause memory leaks if the inner object outlives the outer one.
- Prefer a static nested class when the outer instance is not needed.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a member inner class?
A non-static class declared as a member of another class. Each of its objects is associated with an object of the outer class.
Q2. How do I create an instance of a member inner class?
From outside: Outer.Inner in = outerObj.new Inner();. From an instance method of the outer class: new Inner().
Q3. Can a member inner class access private fields of the outer class?
Yes, directly by name, including private fields and methods.
Q4. Can the outer class access private members of the inner class?
Yes, through a reference to an inner object. Nested and outer classes share private access.
Q5. Can I create an inner class object from a static method?
Only with an explicit outer object, for example new Outer().new Inner(), because a static method has no this.
Q6. What is Outer.this?
An expression inside an inner class that refers to the enclosing outer object, used to resolve name clashes.
Q7. Can a member inner class be private?
Yes. Then only the outer class can use it, as with private iterator implementations.
Q8. Can a member inner class have static members?
Since Java 16, yes. Before that, only static final compile-time constants were allowed.
Q9. What is the compiled name of a member inner class?
Outer$Inner.class.
Q10. How does an inner object know its outer object?
The compiler adds a hidden final field (usually this$0) set through an extra constructor parameter.
Q11. Can member inner classes cause memory leaks?
Yes. The inner object holds a strong reference to its outer object, so a long-lived inner object prevents the outer from being garbage-collected.
Q12. Can an inner class extend another class or implement interfaces?
Yes, just like any class.
Q13. Can an inner class be abstract or final?
Yes. Both modifiers are allowed on member inner classes.
Q14. Can a class extend an inner class of another class?
Yes, but its constructor must supply an outer instance with the unusual syntax outer.super().
Q15. What is the difference between an inner class and a static nested class?
An inner class needs and references an outer instance; a static nested class does not and can be created on its own.
Q16. When should I use a member inner class?
When the inner object is logically part of a specific outer object and needs its state, such as an iterator or a view over a collection.
Q17. Can a member inner class have a constructor?
Yes. It can have any number of constructors; the outer instance is passed implicitly.
Q18. Can I serialize an inner class?
It is strongly discouraged: the hidden outer reference and compiler-generated names make serialized forms fragile. Use a static nested class instead.
Q19. Can an inner class be declared inside an interface?
Classes declared inside an interface are implicitly static, so they are static nested classes, not inner classes.
Q20. Do inner classes affect performance?
Only slightly: each object stores an extra reference. Since Java 11's nestmates, private access no longer needs synthetic accessor methods.