Local Inner Classes
Local inner classes can access variables declared in the enclosing block as long as they are final. When the enclosing block is a constructor or a method the final parameters of the constructor or method are also accessible, of course for reading.
Members of the enclosing class are also accessible regardless of their access modifier. Keep in mind that a class declared in a static block can only access static members of the enclosing class.
Another interesting limitation is the fact that local inner classes cannot declare static blocks. Also a local inner cannot have the same name (hide) as an enclosing class.
The next code sample shows how the syntax for local inner classes looks like.
package com.littletutorials.nested;
public class Outer
{
private static String s = "outer member";
private int a = 1;
static
{
final int b = 2;
int c = 3;
// local inner class in a static block
final class LocalInner
{
public void f()
{
System.out.print(getClass().getName() + " inner in ");
System.out.println(getClass().getEnclosingClass());
System.out.println(s);
System.out.println("b = " + b);
// a = 2; // error: a is not static
// c = 4; // error: a is not final
}
}
LocalInner l = new LocalInner();
l.f();
}
public Outer(final String p1, String p2)
{
int a = 4; // hide the class member
final int b = 5;
// local inner class in a constructor
class LocalInner
{
final String s2 = "inner member";
public void f()
{
// declare a local inner in a method of a local inner
class InnerInner
{
public void f()
{
System.out.print(getClass().getName() + " inner in ");
System.out.println(getClass().getEnclosingClass());
System.out.println(Outer.this.s);
System.out.println(LocalInner.this.s2);
}
}
System.out.print(getClass().getName() + " inner in ");
System.out.println(getClass().getEnclosingClass());
// direct access to members of the top level class
System.out.println(s);
// qualified access to hidden members of the top level class
Outer.this.a = 2;
// access to variables declared in the enclosing block
System.out.println(p1);
// System.out.println(s2); // error: p2 is not final
// a = 5; // error: a is not final
System.out.println("b = " + b);
// use the local inner
InnerInner i = new InnerInner();
i.f();
}
}
// use the local inner
LocalInner l = new LocalInner();
l.f();
}
public static void main(String[] args)
{
Outer o = new Outer("final param", "non-final param");
}
}
When executed the main method of the Outer class declared above will produce this output that reveals the naming conventions used by the compiler for local inner classes:
com.littletutorials.nested.Outer$1LocalInner inner in class com.littletutorials.nested.Outer
outer member
b = 2
com.littletutorials.nested.Outer$2LocalInner inner in class com.littletutorials.nested.Outer
outer member
final param
b = 5
com.littletutorials.nested.Outer$2LocalInner$1InnerInner inner in class com.littletutorials.nested.Outer$2LocalInner
outer member
inner member
Local inner classes can be very useful in declaring classes with a very limited scope and with short implementations. A perfect example are implementations of listener interfaces or extensions of abstract adapters. Other useful scenarios can be imagined, for example the initialization of a map of action classes with unique and short implementations in a static block. These constructs offer the convenience of not creating a new file for a small class and can also help with encapsulation. On the other hand when they are over used they can make the code hard to read and debug and they can become a nightmare for maintainers.
This post is part of a series explaining the Java concept of defining classes in other classes:
- Static Nested Classes
- Static Nested Interfaces
- Inner Classes
- Local Inner Classes
- Anonymous Inner Classes











