There's a very simple program:
public class A {
public static void main(String[] p) {
final Runnable r = new Runnable() {
public void run() {
System.out.println(r);
}
};
r.run();
}
}
And this gives:
$ javac A.java
A.java:6: variable r might not have been initialized
System.out.println(r);
^
1 error
- Why?
- How can a Runnable reference a variable pointing to it?
(In the real code, there is one more level (a listener), and referencing via this
does not work)
In this case, you can use "this" to avoid the compilation error:
final Runnable r = new Runnable() {
public void run() {
System.out.println(this); // Avoid compilation error by using this
}
};
To answer your second question:
Runnable outer = new Object() {
public final Runnable r = new Runnable() {
public void run() {
System.out.println(r);
}
};
}.r;
outer.run();
should work.
Here the compiler sees that r will have been initialized through the implicit constructor.
For your tiny example, it would be enough to move the final Runnable r
outside the main method and say:
new A().r.run();
In this case your new Runnable
is being created before r
, because of order of operations everything to the right side of an assignment operator is performed before the assignment. This means that r
is not in scope when your Runnable is declared, and thus it doesn't know what it is inside the run
method.
There's no r
variable in the scope of your run()
method, you are trying to print out some value during it's initialization... That's why it "might not have been initialized"
.
just use "this" in the Runnable in the place of "r" ))) works fine. Then you do not need to add the "outer" Runnable.
The working code is:
public class A {
public static void main(String[] p) {
class RunnableHolder { Runnable r; };
final RunnableHolder r = new RunnableHolder();
r.r = new Runnable() {
public void run() {
System.out.println(r.r);
}
};
r.r.run();
}
}
So it is possible to "unfinal" a variable using an auxiliary object.
It looks like this construct (an auxiliary object whose fields may be accessed from a Runnable) is exactly what the designers of Java tried to disallow. :)
public class A {
private static Runnable r;
public static void main(String[] p) {
r = new Runnable() {
public void run() {
System.out.println(r);
}
};
}
}
This should work! And there is no r in the scope of run and thus it cannot be found in the anonymous implementation.