So, execute the following code:
import java.lang.reflect.Field;
class Test {
public Test() {
doIt();
}
public void doIt() {}
}
public class TestReflection extends Test {
private final String name = "Immutable";
private String n = "n";
public TestReflection() { }
public void doIt() {
System.out.println("1 = " + name);
System.out.println(n);
System.out.println("-----");
}
public static void main(String[] args) throws Exception {
TestReflection abc = new TestReflection();
Class c1 = Class.forName("TestReflection");
Field field2 = c1.getDeclaredField("name");
field2.setAccessible(true);
System.out.println("2 = " + abc.name);
field2.set(abc, "Mutable");
System.out.println("3 = " + abc.name);
}
}
Output:
1 = Immutable
null
-----
2 = Immutable
3 = Immutable
And the following version of the code:
import java.lang.reflect.Field;
class Test {
public Test() {
doIt();
}
public void doIt() {}
}
public class TestReflection extends Test {
private final String name;
private String n = "n";
public TestReflection() {
name = "Immutable";
}
public void doIt() {
System.out.println("1 = " + name);
System.out.println(n);
System.out.println("-----");
}
public static void main(String[] args) throws Exception {
TestReflection abc = new TestReflection();
Class c1 = Class.forName("TestReflection");
Field field2 = c1.getDeclaredField("name");
field2.setAccessible(true);
System.out.println("2 = " + abc.name);
field2.set(abc, "Mutable");
System.out.println("3 = " + abc.name);
}
}
Output:
1 = null
null
-----
2 = Immutable
3 = Mutable
The answer to this behaviour can be found in JLS (http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html), section 17.5.3,
"Even then, there are a number of complications. If a final field is initialized to a compile-time constant in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the compile-time constant. "