Sorry for the title gore, I did not know how to describe the problem in one line. If you have suggestions, I'm open.
Suppose you have the following class:
public class SomeClass {
// doesn't even need to be final, which is freaky
Runnable memberRunnable = new Runnable() {
public void run() {
SomeOtherClass.someMethod(memberRunnable); // this works
}
}
public void someMethod() {
final Runnable varRunnable = new Runnable() {
public void run() {
SomeOtherClass.someMethod(varRunnable); // compiler error - "varRunnable" might not have been initialized
}
}
}
}
Why is the memberRunnable
able to access itself from inside run()
, while varRunnable
is not? AFAICS it's the exact same construct.
You can obviously use this
instead, I know. I'm just wondering why the compiler makes a difference between the two cases, which seem identical. Also why it thinks varRunnable
might not have been initialized, when it's obvious that it is at that point.
One could argue that, if Runnable
was a class (it's an interface), it's constructor might be trying to call run()
, thus actually running into a scenario where the reference is uninitialized. However, this should also be the case for memberRunnable
, but that case works.
Funny thing, nothing changes if instead of Runnable
you use a class, in which case the above scenario (constructor calling an overridden method) can actually happen. This means that, in that case, you can run into a "field not initialized" at runtime (haven't tried it though), which is rather dumb since the compiler should guard against that.
Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.
It can extend exactly one class and can implement multiple interfaces. It can extend exactly one class and implement exactly one interface. It can implement multiple interfaces regardless of whether it also extends a class. It can extend exactly one class or implement exactly one interface.
Restriction on Anonymous Inner class Anonymous inner class cannot be declared as public, private, protected, or static. It cannot access local variables of its enclosing scope that are not declared as final or effectively final.
Also why it thinks
varRunnable
might not have been initialized, when it's obvious that it is at that point.
No, the variable is not (in the general case) guaranteed to be initialized at that point.
Suppose, just for the sake of argument, that Runnable
was an abstract class (rather than an interface) and that the constructor of Runnable
called this.run()
. Since construction of the Runnable
occurs before the assignment, this would result in access of varRunnable
before the assignment had occurred.
In other words, it would lead to access of an uninitialized local variable. Note that this is worse than accessing a field that has not yet been explicitly initialized, since local variables are not initialized to default values. It's so much worse in fact, that access of uninitialized local variables is forbidden, while access to fields that have not been explicitly initialized is allowed, as you just discovered. (Making the field final doesn't change this. Final fields also have default values, and they can in fact change (once) in the constructor.)
Source: I'm a javac developer.
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