Подтвердить что ты не робот

Объявление переменной конечной и статической

Этот комментарий был сделан в обзоре кода, и человек, который его сделал, больше не находится в нашей команде.

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

Здесь строка кода:

private final static Logger log = LoggerFactory.getLogger(MyClass.class);

Я знаком с дебатами об объявлении журналов статическими или нестатическими, но этот комментарий кажется более общим. Я не могу найти никаких объяснений, почему статические и конечные плохие. Может кто-нибудь уточнить?

4b9b3361

Ответ 1

Комментарий, скорее всего, связан с проблемой утечки Classloader (вот хорошая статья).

Вкратце, эта проблема возникает в средах, где загрузчик классов необходимо перезагрузить. Если вы загружаете класс динамически через загрузчик классов, а затем попробуйте перезагрузить загрузчик классов, сохранение статических конечных полей с объектами классов, созданных с помощью этого загрузчика классов, предотвратит разгрузку самого загрузчика классов. Как только это произойдет, вы получите OutOfMemoryError.

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

Ответ 2

Строка кода совершенно прекрасна, и нет реальной проблемы, потому что переменная final и static.

Возможно, тот, кто сделал этот комментарий, был смущен следующим.

В Java, когда вы создаете переменную public final static типа int (например, она также работает с некоторыми другими типами), тогда компилятор может в тех местах, где вы используете эту переменную, заменить фактическое постоянное значение вместо ссылки на переменную. Например, предположим, что у вас есть следующее:

class A {
    public final static int VALUE = 3;
}

public class B {
    public static void main(String[] args) {
        System.out.println(A.VALUE);
    }
}

Когда вы скомпилируете и запустите это, он, очевидно, напечатает 3.

Теперь предположим, что вы меняете класс A и устанавливаете VALUE = 4. Вы ожидаете, что если вы перекомпилируете класс A, а затем запустите класс B (без перекомпиляции класса B), вы увидите 4. Но произойдет то, что вы все равно увидите 3. Это связано с тем, что A.VALUE в классе B был заменен фактическим значением константы 3 при компиляции класса B.

Это оптимизация, которую компилятор Java делает для констант.

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

Но в коде, опубликованном в вашем вопросе, это не проблема, потому что переменная private.

Подробнее:

Спецификация языка Java 13.4.9