Константы и переменные времени компиляции
Язык документации по Java утверждает:
Если примитивный тип или строка определены как константа, и значение известно во время компиляции, компилятор заменяет имя константы повсюду в коде на его значение. Это называется константой времени компиляции.
Я понимаю, что если у нас есть следующий фрагмент кода:
private final int x = 10;
То компилятор заменит каждое вхождение x
в коде на литерал 10
.
Но предположим, что константа инициализируется во время выполнения:
private final int x = getX(); // здесь getX() возвращает целое значение во время выполнения.
Будет ли наблюдаться снижение производительности (как бы незначительно оно ни было) по сравнению с константой времени компиляции?
Еще один вопрос: будет ли следующая строка кода:
private int y = 10; // здесь y не является final
обрабатываться компилятором так же, как константа времени компиляции?
В конечном итоге, из ответов я понимаю следующее:
final static
означает константу времени компиляции.- Просто
final
означает, что это константа, но она инициализируется во время выполнения. - Просто
static
означает, что она инициализируется во время выполнения. - Без
final
это переменная и не будет рассматриваться как константа.
Правильна ли моя интерпретация?
5 ответ(ов)
Компилируемая константа должна:
- быть объявлена как
final
- быть примитивным типом или строкой
- инициализироваться при объявлении
- инициализироваться с помощью константного выражения
Таким образом, выражение private final int x = getX();
не является константой.
Что касается второго вопроса, то private int y = 10;
также не является константой (поскольку не final
), поэтому оптимизатор не может быть уверенным в том, что значение не изменится в будущем. Следовательно, он не сможет оптимизировать его так же, как константное значение. Ответ: Нет, оно не обрабатывается так же, как компилируемая константа.
Ключевое слово final
означает, что переменная будет инициализирована один раз и только один раз. Реальная константа должна быть также объявлена как static
. Поэтому ни один из ваших примеров не рассматривается компилятором как константа. Тем не менее, ключевое слово final
указывает вам (и компилятору), что ваши переменные будут инициализированы только один раз (в конструкторе или непосредственно при объявлении).
Если вам нужно, чтобы их значения присваивались на этапе компиляции, ваши поля должны быть статическими.
Что касается производительности, то она на самом деле не очень затрагивается, но имейте в виду, что примитивные типы неизменяемы; как только вы их создали, они будут удерживать это значение в памяти до тех пор, пока сборщик мусора не удалит их. То есть, если у вас есть переменная y = 1;
, а затем вы изменяете её на y = 2;
, в памяти у JVM будут храниться оба значения, но ваша переменная будет "указывать" на последнее.
private int y = 10; // здесь y не является final
Обрабатывается ли это так же, как константа времени компиляции компилятором?
Нет. Это экземплярная переменная, создаваемая, инициализируемая и используемая во время выполнения.
Возможно, на некоторых машинах будет очень маленькое снижение производительности при использовании private final int x = getX();
, так как это подразумевает хотя бы один вызов метода (к тому же, это не является константой времени компиляции). Но, как вы и сказали, это будет незначительно, так зачем беспокоиться?
Что касается второго вопроса: y
не является final
, следовательно, это не константа времени компиляции, так как она может изменяться во время выполнения.
В данном коде переменная x
не является константой времени компиляции. Хотя она объявлена с модификатором final
, значение ей присваивается в рантайме. Это означает, что компилятор не может определить значение x
на этапе компиляции. Если бы вы хотели, чтобы x
был константой времени компиляции, вам нужно было бы задать ему значение непосредственно при объявлении, например:
public static void main(String[] args) {
final int x = 5; // Теперь x является константой времени компиляции
}
Теперь компилятор знает, что x
всегда будет равен 5
, и это можно использовать в любом месте, где требуется константа времени компиляции.
Перевод ответа на вопрос на StackOverflow:
private final int x = getX();
Этот код вызовет метод getX()
в момент, когда ваш объект будет создан. Замедление производительности будет зависеть от реализации самой функции getX()
, но в большинстве случаев это не создаст серьезных узких мест в вашем коде. Если getX()
выполняет сложные или времязатратные операции, то это стоит учитывать, иначе, в общем случае, такой вызов не должен вызывать значительных проблем с производительностью.
StringBuilder против конкатенации строк в toString() в Java
Почему 2 * (i * i) быстрее, чем 2 * i * i в Java?
Какова цель использования "final class" в Java?
Эффективен ли метод System.arraycopy() в Java для малых массивов?
Знаете ли вы о каких-либо инструментах для анализа логов сборки мусора в Java? [закрыто]