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; } }