Accessing Outer Class Local Variables from Inner Class Methods

When you try to compile the following Java code, you will get this error,

local variable a is accessed from within inner class; needs to be declared final

public class Outer {

    public void test() {
        int a = 10;
        Runnable i = new Runnable() {

            @Override
            public void run() {
                int j = a * a;
            }
        };
    }
}

The simplest solution to fix this error is to declare the outer class local variable as final. The fixed code is given below,

public class Outer {
    public void test() {
        final int a = 10;
        new Object() {
            public void test2() {
                int j = a * a;
            }
        };
    }
}

Why outer class local variables cannot be accessed from inner class methods?

Java language doesn't support full fledged closures. So whenever an outer class local variable is accessed from inner class methods, Java passes a copy of the variable via auto generated inner class constructors. However if the variable is modified later in the outer class, it can create subtle errors in the program because effectively there are two copies of the variable which the programmer assumes to be the same instance. In order to remove such subtle errors, Java mandates that only final local variables from the outer class method can be accessed in the inner class methods. Since final variables cannot be modified, even though a copy is made for inner class, effectively both instance values remain the same.

However in the case of outer class member variables, this is not an issue. This is because during the entire life time of inner class, an active instance of the outer class is available. Hence the same outer class instance variable is shared by the inner class.

So there are basically two options to pass data from outer class to inner class,

  • Use final local variables in the outer class method
  • Use member variables in outer class

This means that passed local variables cannot be modified from the inner class method. However this restriction can be easily bypassed by using an array or a wrapper class. The following example shows modifying the passed in local variable from the inner class by using an array wrapper,

public class Outer {
    public void test() {
        final int a[] = { 10};
         Runnable i = new Runnable() {
            @Override
            public void run() {
                a[0] = a[0] * a[0];
            }
        };
        i.run();
        System.out.println(a[0]);
    }
    
    public static void main(String[] args) {
        new Outer().test();
    }
}