Java – why does shadow affect ‘final’ behavior?
Here are three sscces. I think they should be compiled and behave the same The only thing I want to change is the first line "run"
Chart 1
public class FinalExperiment {
private TinyThing thing;
public static void main(String[] args) {
FinalExperiment instance = new FinalExperiment();
instance.run();
}
public void run() {
final TinyThing thing = new TinyThing();
System.out.println("Got a thing here: " + thing);
}
private static class TinyThing {
public TinyThing() {}
public String toString() { return "Hello!"; }
}
}
This is valid; It compiles successfully and prints: "one thing: Hello!"
Chart 2
public class FinalExperiment {
private TinyThing thing;
public static void main(String[] args) {
FinalExperiment instance = new FinalExperiment();
instance.run();
}
public void run() {
final TinyThing otherThing = thing;
System.out.println("Got a thing here: " + otherThing);
}
private static class TinyThing {
public TinyThing() {}
public String toString() { return "Hello!"; }
}
}
This is valid; It compiles successfully and prints: "there's something here: null"
Chart 3
public class FinalExperiment {
private TinyThing thing;
public static void main(String[] args) {
FinalExperiment instance = new FinalExperiment();
instance.run();
}
public void run() {
final TinyThing thing = thing;
System.out.println("Got a thing here: " + thing);
}
private static class TinyThing {
public TinyThing() {}
public String toString() { return "Hello!"; }
}
}
Unable to compile with this message:
FinalExperiment.java:10: error: variable thing might not have been initialized
final TinyThing thing = thing;
^
1 error
Why? The only difference between figure 2 and figure 3 is that I hide something in the running method It seems that the compiler should not pay more attention simply because shadows are happening
Solution
Yes, a shadow occurs in Figure 3, but you are actually trying to declare a final variable and assign it to yourself
final TinyThing thing = thing; // Assign to self!
It has not been assigned a value, so you will receive an uninitialized compiler error This happens whether the local variable is final or not
To reference instance variables, use this qualification
final TinyThing thing = this.thing; // Bypass shadowing.
This will compile and result in the same output as Figure 2:
Got a thing here: null
This sample cannot be compiled in the same way, for example:
public class SelfDefineExample {
public static void main(String[] args) {
int i = i;
}
}
