1

When I try to change the value of a static final member of a nested static class I don't see it working. When I try the below code to change the static final member of some other class it works.

   public class FinalPivateStaticMember {

        public static void main(String[] args) {
            System.out.println("Initial value == "+Test.val);
            try {
                Class cls = Class.forName("com.reflection.FinalPivateStaticMember$Test");
                try {
                    Field file_systems_loaded = cls.getDeclaredField("val");
                    file_systems_loaded.setAccessible(true);

                    Field modifiers = Field.class.getDeclaredField("modifiers");
                    modifiers.setAccessible(true);
                    try {
                        System.out.println("--"+file_systems_loaded.getModifiers());
                        modifiers.setInt(file_systems_loaded,file_systems_loaded.getModifiers() & ~Modifier.FINAL);
                        System.out.println("--"+file_systems_loaded.getModifiers());
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    try {
                        file_systems_loaded.setBoolean(null,false);
                    } catch (IllegalAccessException e) {
                            e.printStackTrace();
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
            } catch (ClassNotFoundException e) {
                    e.printStackTrace();
            }
            System.out.print("Final value == "+Test.val);

        }

        static class Test{

           private  static final  boolean val = true;
        }

    }

Output of above code

Initial value == true
--26
--10
Final value == true
4
  • maybe that using a getter is somewhat different than accessing the field directly... The compiler is known for 'inlining' constant values, actually if you change a constant field (public static final) in one class and do not recompile other classes that use that field, they will still have/use the old value. Commented Feb 8, 2018 at 18:58
  • this is explained in the Java Language Specification: docs.oracle.com/javase/specs/jls/se9/html/… Commented Feb 8, 2018 at 19:04
  • As a side note, Class.forName("com.reflection.FinalPivateStaticMember$Test") doesn’t gain you anything over the much simpler Test.class. Commented Feb 9, 2018 at 11:29
  • @CarlosHeuberger of course, using a getter doesn’t change anything, the access within the getter method gets inlined as any other access. But besides the fact that val is a compile-time constant, modifying static final fields is off specification anyway and not guaranteed to work. Commented Feb 9, 2018 at 11:31

1 Answer 1

1

The value is actually changing, but you don't see the change in your print statements because of compiler optimization. The compiler can (and will) replace the occurrences of primitive (and String) static final fields with the value they hold. So after compilation your print statements would be equivalent to

System.out.print("Final value == "+true)

Note that the variable is replaced with it's source value during compilation phase itself.

Sign up to request clarification or add additional context in comments.

1 Comment

The behavior regarding compile-time constants is more than an optimization, it’s a mandatory behavior. Since string concatenation with compile-time constants results in a compile-time constant as well, the actual compiled code is equivalent to System.out.print("Final value == true");

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.