Константы и переменные времени компиляции

документация языка Java говорит:

если примитивный тип или строка определяется как константа и значение известен во время компиляции, компилятор заменяет имя константы везде в коде со своим значением. Это называется компиляции постоянный.

насколько я понимаю, если у нас есть кусок кода:

private final int x = 10;

затем компилятор заменит каждое вхождение x в коде с буквальным 10.


но предположим, что константа инициализируется во время выполнения:

private final int x = getX(); // here getX() returns an integer value at run-time.

будет ли какое-либо падение производительности (как бы незначительно оно ни было) по сравнению с константой времени компиляции?


другой вопрос, Является ли ниже строку кода:

private int y = 10; // here y is not final

обрабатывается компилятором так же, как константа времени компиляции?


наконец, что я понимаю из ответов являются:

  1. final static означает константу времени компиляции
  2. просто final означает, что это константа, но инициализируется во время выполнения
  3. просто static значит инициализирован во время выполнения
  4. без final является переменной и не будет рассматриваться как константа.

правильно ли я понимаю?

7 ответов


константа времени компиляции должна быть:

  • объявлен Final
  • примитив или строка
  • инициализировать в объявлении
  • инициализирована константным выражением

Так private final int x = getX(); не является постоянным.

второй вопрос private int y = 10; не является постоянным (в данном случае не конечным), поэтому оптимизатор не может быть уверен, что значение не изменится в будущем. Поэтому он не может оптимизировать его так же хорошо, как постоянное значение. Ответ: Нет, он не рассматривается так же, как константа времени компиляции.


на final ключевое слово означает, что переменная будет проинициализирована только один раз. Реальная постоянная должна быть объявлена static Как хорошо. Таким образом, ни один из ваших примеров не рассматривается компилятором как константы. Тем не менее, ключевое слово final сообщает вам (и компилятору), что ваши переменные будут инициализированы только один раз (в конструкторе или буквально). Если вам нужны их значения, назначенные во время компиляции, ваши поля должны быть статическими.

производительность на самом деле не так влияет, но имейте в виду, что примитивные типы неизменяемы, как только вы создали один, он будет удерживать это значение в памяти, пока сборщик мусора не удалит его. Итак, если у вас есть переменная y = 1; и затем вы меняете его на y = 2; в памяти JVM будет иметь оба значения, но ваша переменная будет "указывать" на последнее.

private int y = 10; / / здесь y не является окончательным

обрабатывается так же, как константа времени компиляции компилятором ?

нет. Это переменная экземпляра, созданная, инициализированная используемой во время выполнения.


здесь может быть очень маленький падение производительности на некоторые машины для private final int x = getX(); поскольку это будет включать по крайней мере один вызов метода (кроме того, что это не константа времени компиляции), но, как вы сказали, это будет л так зачем?

что касается второго вопроса: y не является окончательным и, следовательно, не является константой времени компиляции, так как она может измениться во время выполнения.


private final int x = getX(); Будет вызываться при первом объявлении объекта. Производительность "drop" будет зависеть от getX() но это не те вещи, которые создают какое-то узкое место.


согласно JLS, нет требования, что" постоянная переменная " должна быть статической.

поэтому "постоянная переменная" может быть статической или нестатической (переменная экземпляра).

но JLS накладывает некоторые другие требования для переменной, чтобы быть " постоянной переменной "(кроме того, просто окончательной):

  • быть только строкой или примитивные
  • инициализируется только inline, потому что это final, а пустой final не допускается
  • инициализирован с "constant expression" = "выражение константы времени компиляции" (см. цитату JLS ниже)

4.12.4. конечные переменные (JLS)

A постоянная переменная - конечная переменная примитивного типа или типа String, которая инициализируется постоянным выражением (§15.28).

15.28. Постоянные Выражения

A выражение константы времени компиляции - выражение, обозначающее значение примитивного типа или строки, которая не завершается резко и составлено, используя только следующее:

литералы примитивного типа и литералы типа String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)

приводит к примитивным типам и приводит к типу String (§15.16)

унарные операторы +, -, ~ и ! (но не ++ или --) (§15.15.3, §15.15.4, §15.15.5, §15.15.6)

мультипликативные операторы *, / и % (§15.17)

аддитивные операторы + и - (§15.18)

операторы сдвига >, и >>> (§15.19)

операторы отношения и > = (но не instanceof) (§15.20)

операторы равенства == и != (§15.21)

побитовые и логические операторы &, ^ и | (§15.22)

условное-и оператор && и оператор conditional-or || (§15.23, §15.24)

тернарный условный оператор ? : (§15.25)

заключенные в скобки выражения (§15.8.5), содержащее выражение константное выражение.

простые имена (§6.5.6.1), которые относятся к постоянным переменным (§4.12.4).

полные имена (§6.5.6.2) формы TypeName . Идентификатор обозначения постоянных величин (§4.12.4).


на JLS делает следующие различия между final переменные и константы:

final переменные

переменная может быть объявлена final. А final переменной может быть только назначено на один раз. Это-ошибка времени компиляции, если final переменная назначается, если он определенно не назначен непосредственно перед задание (§16 (Определенного Назначения)).

после final переменная была назначена, она всегда содержит одно и то же значение. Если a final переменная содержит ссылку на объект, затем состояние объекта может быть изменено операциями над объектом, но переменная всегда будет ссылаться на тот же объект. Это также относится для массивов, потому что массивы являются объектами; если final переменная содержит a ссылка на массив, затем компоненты массива могут быть изменены по операциям над массивом, но переменная всегда будет ссылаться на тот же матрица.

A пробел final это final переменная, в объявлении которой отсутствует инициализатор.

константы

A постоянная переменная это final переменная примитивного типа или типа String инициализируется постоянным выражением (§15.28).

из этого определения мы можем заметить, что константа должна быть:

  • объявил final
  • примитивного типа или типа String
  • инициализировано в его объявлении (не пробел final)
  • инициализации с константное выражение

как насчет констант времени компиляции?

на JLS не содержит фразу константа времени компиляции. Однако программисты часто используют термины константа времени компиляции и постоянный взаимозаменяемо.

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


каждый примитивный литерал и строковый литерал является константой времени компиляции.

см.:https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28