There are some topics on Stack Overflow on the compiler error Cannot refer to a non-final variable message inside an inner class defined in a different method
and the solution is "declare it as final and you're done", but with this theoretical question I would like to inspect what is the logical reason why this code cannot compile:
private void updateStatus(String message) { Runnable doUpdateStatus = new Runnable() { public void run() { /* do something with message */ } } /* do something with doUpdateStatus, like SwingUtilities.invokeLater() */ }
(solution: declare message
as final) whereas this one does:
private String enclosingClassField; private void updateStatus() { Runnable doUpdateStatus = new Runnable() { public void run() { /* do something with enclosingClassField */ } } /* do something with doUpdateStatus, like SwingUtilities.invokeLater() */ }
I'm really confused. enclosingClassField
is not final, it can change every time many times, whereas the poor message
argument of updateStatus
can only change within its method body, and is instead blamed by the compiler ;)
Even the compiler error is misleading to me. Cannot refer to a non-final variable message inside an inner class defined in a different method
: Different from what? Isn't message
defined in the same method as the inner class? Isn't enclosingClassField
instead defined outside the method? Uhm...
Can someone point me to the correct interpretation of this matter? Thanks.
A local inner class cannot be instantiated from outside the block where it is created in. Till JDK 7, the Local inner class can access only the final local variable of the enclosing block. However, From JDK 8, it is possible to access the non-final local variable of enclosing block in the local inner class.
Yes, we can access the local final variables using the method local inner class because the final variables are stored on the heap and live as long as the method local inner class object may live.
Accessing Members of an Enclosing Class In addition, a local class has access to local variables. However, a local class can only access local variables that are declared final.
A local class can only access local variables that are declared final in java.
The difference is between local (method) variables vs class member variables. A member variable exists during the lifetime of the enclosing object, so it can be referenced by the inner class instance. A local variable, however, exists only during the method invocation, and is handled differently by the compiler, in that an implicit copy of it is generated as the member of the inner class. Without declaring the local variable final, one could change it, leading to subtle errors due to the inner class still referring to the original value of that variable.
Update: The Java Specialists' Newsletter #25 discusses this in more detail.
Even the compiler error is misleading to me.
Cannot refer to a non-final variable message inside an inner class defined in a different method
: Different from what?
From the inner class' run
method I believe.
The reason is that Java doesn't support closures. There are no JVM commands to access local variable from outside the method, whereas fields of class can be easily accessed from any place.
So, when you use final
local variable in an inner class, compiler actually passes a value of that variable into constructor of the inner class. Obviously, it won't work for non-final
variables, since they value can change after construction of the inner class.
Fields of containing class don't have this problem, because compiler implicitly passes a reference to the containing class into the constructor of the inner class, thus you can access its fields in a normal way, as you access fields of any other class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With