Не удалось изменить частную конечную статическую переменную без исключения - PullRequest
2 голосов
/ 30 августа 2011

Я пытался изменить приватную конечную статическую переменную, например 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;
     }

Однако TargetA.RECV_TIMEOUT по-прежнему 180000L, без каких-либо исключений.Я искал проблему в StackOverflow, но не смог найти решение.

Я предполагаю, что версия Java 1.6 имеет больше ограничений в отражении, что нарушает правила OO.Спасибо за ваш совет!

Ответы [ 3 ]

7 голосов
/ 30 августа 2011

Таким образом, вы можете изменить статическое конечное поле, и если вы посмотрите на значение, используя отражение, оно будет изменено. Проблема, с которой вы столкнулись, заключается в том, что компилятор выполняет одну-единственную оптимизацию, которая заключается в том, что встроенные константы знают во время компиляции. Это означает, что значение может быть изменено, однако места, где используется константа, не изменены.

Способ обойти это - использовать метод-обертку, чтобы «запутать» компилятор, чтобы избежать необходимости менять способ использования константы.

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

public static final <T> T runtime(T t) { return t; }
5 голосов
/ 30 августа 2011

Модификация полей final через отражение имеет много ограничений.В частности, если поле final инициализируется константой времени компиляции, его новое значение может не наблюдаться ( JLS 17.5.3 Последующая модификация конечных полей ).

Вы можетеиспользуйте следующий обходной путь:

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

     private static long defaultTimeout() { return 180000L; }
} 
0 голосов
/ 30 августа 2011

Попробуйте добавить следующий код после внесения изменений, и вы увидите, что он изменился.

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

Однако, как указывает Питер

Это означает, что значение может бытьизменить, однако места, где используется константа, не изменились.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...