Search code examples
javaeclipsestaticfinalintrospection

Eclipse and println seem to disagree on value of dynamically-set private final static field


While playing with introspection, I found an interesting situation where:

  • Eclipse's debugger tooltip displays true
  • println prints false (note the output in the Console tab):

eclipse

I am trying to set the value of the private final static field, I guess I did it wrong?
What is actually happening here?

import java.lang.reflect.*;

public class Main {

    private final static boolean VAR = false; // I want to dynamically set this to true

    public static void main(String[] args) throws Exception {
        Field field = Main.class.getDeclaredField("VAR");
        field.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.set(null, true);
        System.out.println(VAR);
    }
}

Solution

  • The compiler is 'inlining' the static final value. If you look at the bytecode for the println you will see something like:

    iconst_0
    invokevirtual java.io.PrintStream.println(boolean) 
    

    Because it knows the value won't change the compiler has generated code which is loading the value 0 (for false) directly without referring to the VAR variable so your change to the variable is ignored.

    Because of the inlining you can't rely on being able to change the value of a static final variable with reflection.