Что значит сказать, что шаблоны int enum являются константами времени компиляции?

Это из эффективной Java

Программы, использующие шаблон int enum, ненадежны. Поскольку перечисления int являются константами времени компиляции, они компилируются в клиенты, которые их используют.

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

Вот пример такой константы:

public static final int APPLE_FUJI = 0;

person Geek    schedule 02.08.2012    source источник
comment
Это одна из немногих оптимизаций, которые javac делает, и в целом я бы предпочел, чтобы этого не было ;)   -  person Peter Lawrey    schedule 02.08.2012


Ответы (2)


Предположим, у вас есть два файла:

Foo.java:
public class Foo
{
    public static final int SOMETHING = 1;
}

Bar.java:
public class Bar
{
    public static void main(String[] args)
    {
        System.out.println(Foo.SOMETHING);
    }
}

Скомпилируйте их оба, запустите java Bar и он выведет 1.

Теперь измените Foo.java так, чтобы SOMETHING равнялось 2, и перекомпилируйте только Foo.java. Повторно запустите java Bar, и он по-прежнему напечатает 1. Постоянное значение будет скопировано в каждый фрагмент кода, который его использует, вместо того, чтобы запрашивать значение из Foo во время выполнения.

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

person Jon Skeet    schedule 02.08.2012
comment
разве Java не язык динамической привязки? Почему мы должны перекомпилировать все? - person Geek; 02.08.2012
comment
@Geek Вы не должны это делать. Но это настоятельно рекомендуется, чтобы избежать того, что Джон Скит описывает выше. Такое поведение компилятора Java, на мой взгляд, плохо. Эта константа должна храниться только в Foo.class. Bar должен ВСЕГДА получать эту константу от Foo. Как и многие другие полуглупые вещи в языке: это не будет изменено, потому что, возможно, это сломает существующий код. Какие плаксы... - person Radu Murzea; 02.08.2012
comment
@Geek: вам нужно определить язык динамической привязки, чтобы я ответил на ваш первый вопрос. Но причина, по которой вы должны перекомпилировать в этом случае, заключается в том, что спецификация языка явно вызывает константные выражения, подобные этому. - person Jon Skeet; 02.08.2012
comment
@Jon динамическая привязка в том смысле, что клиенты Foo должны запрашивать у Foo любую константу, принадлежащую Foo во время выполнения (т.е. динамическую). - person Geek; 02.08.2012
comment
Типы (классы) связаны динамически, но, как уже упоминалось, константы — нет. Это оптимизация. Если вы хотите сохранить динамическую типизацию, используйте настоящие перечисления вместо констант int. - person Adriaan Koster; 02.08.2012

Само значение '0' будет встроено в файлы .class во время компиляции. Если вы затем измените это значение, вам придется перекомпилировать все, что его использует, включая любой клиентский код, использующий ваше приложение/библиотеку.

Если вы этого не сделаете, вы получите не предупреждение, а скорее некорректное поведение.

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

person Brian Agnew    schedule 02.08.2012