开发者

Fail to modify private final static variable without Exception

开发者 https://www.devze.com 2023-03-31 22:05 出处:网络
I tried to modify private final static variable like this: ...try { Field f =TargetA.class.getDeclaredField(\"RECV_TIMEOUT\");

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.printStackTr开发者_高级运维ace();//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!


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; }


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; }
} 


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消