2

I tried to modify private final static variable like this:

    ...try {

        Field f =TargetA.class.getDeclaredField("RECV_TIMEOUT");
        f.setAccessible(true);

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

        f.set(null, 12L);

    } catch (Exception e) {
        e.printStackTrace();//not reach here!
    } ...

    class TargetA{
        private static final long RECV_TIMEOUT = 180000L;
     }

However TargetA.RECV_TIMEOUT is still 180000L, without any Exception. I searched the problem in StackOverflow, but couldn’t find solution.

I guess the Java version1.6 has more restriction in reflection which breaks OO rules. Thanks for your advice!

Community
  • 1
  • 1
卢声远 Shengyuan Lu
  • 31,208
  • 22
  • 85
  • 130

3 Answers3

7

You can change the static final field this way and if you look at the value using reflection it will be changed. The problem you have is that the compiler does one and only one optimisation which is to inline constants know at compile time. This means the value can be change, however the places where the constant is used is not changed.

A way around this is to use a wrapper method to "confuse" the compiler, which avoid having to change how you use the constant.

public static final long RECV_TIMEOUT = runtime(180000L);

public static final <T> T runtime(T t) { return t; }
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
5

Modification of final fields via reflection has many limitations. In particular, if final field is initialized by a compile-time constant, its new value may not be observed (JLS 17.5.3 Subsequent Modification of Final Fields).

You can use the following workaround:

class TargetA{
     private static final long RECV_TIMEOUT = defaultTimeout();     

     private static long defaultTimeout() { return 180000L; }
} 
axtavt
  • 239,438
  • 41
  • 511
  • 482
0

Try to add the following code after your change and you will see that it has changed.

Field e =TargetA.class.getDeclaredField("RECV_TIMEOUT");
e.setAccessible(true);
System.out.println(e.getLong(modifiersField));

However as quoted from Peter

This means the value can be change, however the places where the constant is used is not changed.