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
Pushparaj
  • 1,039
  • 1
  • 6
  • 26
  • 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. – user85421 Feb 08 '18 at 18:58
  • this is explained in the Java Language Specification: https://docs.oracle.com/javase/specs/jls/se9/html/jls-13.html#jls-13.4.9-300 – user85421 Feb 08 '18 at 19:04
  • As a side note, `Class.forName("com.reflection.FinalPivateStaticMember$Test")` doesn’t gain you anything over the much simpler `Test.class`. – Holger Feb 09 '18 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. – Holger Feb 09 '18 at 11:31

1 Answers1

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.

Codebender
  • 14,221
  • 7
  • 48
  • 85
  • 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");`… – Holger Feb 09 '18 at 11:10