Member Inner Class in Java
A member inner class is a class declared directly inside another class's body, without static. Every object of it is bound to one object of the outer class, the way a dashboard is bound to one car. Through that bond it can read and change the outer object's fields, even private ones, as if they were its own. That makes inner classes ideal for "views" of an outer object, such as an iterator over a custom collection.
A Playlist and Its Iterator
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Playlist implements Iterable<String> {
private final String owner;
private final String[] songs;
Playlist(String owner, String... songs) {
this.owner = owner;
this.songs = songs;
}
public Iterator<String> iterator() {
return new SongIterator();
}
private class SongIterator implements Iterator<String> {
private int next = 0;
public boolean hasNext() { return next < songs.length; }
public String next() {
if (!hasNext()) throw new NoSuchElementException();
return (next + 1) + ". " + songs[next++]
+ " (" + Playlist.this.owner + ")";
}
}
public static void main(String[] args) {
Playlist list = new Playlist("Advitha", "Morning Raga", "Monsoon Walk");
for (String s : list) {
System.out.println(s);
}
}
}1. Morning Raga (Advitha)
2. Monsoon Walk (Advitha)How it works
SongIteratoris a private member inner class: no other class can see it.- It reads
songs, a private field ofPlaylist, directly. Each iterator has its ownnextposition. Playlist.this.ownernames the outer object explicitly. Plainownerwould also work here; the qualified form is needed when the inner class has its own field with the same name.iterator()is an instance method, sonew SongIterator()automatically ties the new iterator tothisplaylist. The for-each loop callsiterator()behind the scenes.
Creating One from Outside
Inside the outer class's instance methods, new Inner() uses this as the outer object. Anywhere else, you must say which outer object:
Car car = new Car("Navika", new Car.Engine(1197));
Car.Dashboard dash = car.new Dashboard(); // the dashboard for this carFrom a static method such as main, plain new Inner() fails, because there's no this:
NoOuter.java:4: error: non-static variable this cannot be referenced from a static context
Inner i = new Inner();
^
1 errorThe Hidden Reference
The compiler gives every inner object a hidden field, this$0, pointing to its outer object. Two consequences follow:
- Every inner object is slightly bigger than a static nested one.
- As long as an inner object is reachable, its outer object is too. A long-lived listener or task created as an inner class of a big screen or service can keep that whole object in memory, which is a classic memory leak.
Rules
| Rule | Detail |
|---|---|
| Access to outer members | All of them, including private |
| Outer's access to inner members | Also all, including private |
| Static members inside an inner class | Allowed since Java 16 |
| Access modifiers on the inner class | Any: private hides it completely |
| Same-named fields | Use Outer.this.field for the outer one |
Common Mistakes
Calling new Inner() from a static method. Create an outer object first: outer.new Inner().
Keeping inner objects longer than their outer object should live. They pin the outer object in memory.
Using an inner class where a static nested class would do. It adds an unused reference and blocks garbage collection.
Practice
- Easy: Add a member inner class
SummarytoPlaylistwith a method that returns the owner's name and the number of songs. - Harder: Write a
Classroomclass with a privateString[] studentsand a member inner class that iterates over the students in reverse order.
Key Takeaways
Was this tutorial helpful?