заключительные неизменяемые константы Java - PullRequest
0 голосов
/ 28 февраля 2012

Можно ли запретить встраивание финальных строк? Возможно, это странное требование, но мне нужно изменить окончательное значение поля во время выполнения. Это необходимо для юнит-тестирования.

Например:

class asd {
    public static final String value = "sdfmsdkofl";

    public String getValue() {
        return value;
    }
}

Мне нужно как-то избежать вставки переменной value. И я не могу изменить исходный код :(. Это означает, что я не могу изменить способ доступа к полю, добавить геттеры и сеттеры.

Некоторые магические параметры, которые отключали бы ALL оптимизаций, даже такие простые.

Ответы [ 2 ]

1 голос
/ 28 февраля 2012

Вы не можете.Единственный возможный обходной путь - сделать константу не final, что делает ее, ну, не константой.То, что вы должны делать, это реорганизовать ваш код, чтобы он мог быть протестирован без такого безумия.

0 голосов
/ 29 февраля 2012

Hm.Первое замечание: это ПЛОХО, что нужно делать в производственном коде.Я сделал это в тестах (для переключения драйвера JDBC), но это не очень хорошая идея.Но: это, вероятно, выполнимо, если вы делаете это достаточно рано.JavaC (если вы используете Oracle) не оптимизирует, все это делает JIT.Итак, если вы измените его до того, как JIT сделает свое волшебство, тогда все будет хорошо.Теоретически, вы должны иметь возможность изменять значение и после оптимизации во время выполнения, поскольку код JIT: ed должен быть помечен как недействительный после того, как вы изменили строку, но здесь я действительно катаюсь по очень тонкому льду.

Это (части) моего тестового кода.

Мне нужно изменить драйвер в этом классе:

class MysqlConnection {
   private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";

    protected Connection instantiateNewConnection() {
    try {
        // The newInstance() call is a work around for some 
        // broken Java implementations

        Class.forName(DRIVER_NAME).newInstance();
    } catch (Exception ex) {
        // handle the error 
        LOG.info("Class Exception: " + ex);
    }
}
}

И я делаю это так:

class DBOperation {
    static {
        Field f = MysqlConnection.class.getDeclaredField("DRIVER_NAME");
        f.setAccessible(true);
        f.set(f, LocalFlipper.HSQLDB_DRIVER);
    }
}

Это работает.Можно изменить окончательные поля в Java, но это не очень хорошая идея.Сначала я изменяю рассматриваемое поле, затем создаю экземпляр экземпляра, и поле DRIVET_NAME содержит драйвер jdbc, который я хочу.

Кажется, есть некоторые сомнения относительно того, будет ли это работать или нет, но я могу заверить вас в этомдействительно, попробуйте это для себя.

@ LouisWasserman: Я ушел и javap: ed части кода:

Class.forName(DRIVER_NAME).newInstance();

соответствует

   28:  ldc     #16; //String com.mysql.jdbc.Driver
   30:  invokestatic    #17; //Method  java/lang/Class.forName(Ljava/lang/String;)Ljava/lang/Class;
   33:  invokevirtual   #18; //Method java/lang/Class.newInstance:()Ljava/lang/Object;

Как видите, строка являетсяне встроенныйКроме того, как вы встраиваете объект (или сложный тип)?Вы можете вставить ссылку (естественно).Я согласен, что если у нас есть код, такой как

Class.forName("com.mysql.jdbc.Driver");

, то у нас нет способа получить доступ к этой строке, поскольку мы не можем получить ссылку на нее.

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