Первый оператор корректен ... хотя и ограничен final
полями экземпляров.
Второй оператор неверен.
Переменная final
будет занимать память где-то во время выполнения.Однако, где эта память зависит от типа переменной, которую вы объявляете как final
.
Если переменная является локальной переменной или переменной формального аргумента метода, то ячейка памяти будетбыть в стеке.
Если переменная является нестатическим полем, то ячейка памяти будет частью объекта и будет в куче.
Если переменная является статическим полем, то расположение ячейки памяти будет зависеть от реализации.(Это может быть в куче или в другом месте.)
Следует отметить, что некоторые (но не все!) Поля static final
являются константами компиляции,и их значения эффективно указываются компилятором.Но даже когда это произойдет, все равно будет действительное поле, которое занимает ячейку памяти во время выполнения, и к содержимому этой ячейки памяти можно будет обращаться рефлексивно.
(Действительно, вы даже можете рефлексивно изменять поле final
. Когда вы это делаете, поведение не определяется спецификацией JVM, и в некоторых случаях может быть довольно неожиданным.)
Конечные переменные занимают память для каждого экземпляра?
Нет, потому что:
- статические переменные не "занимают память надля каждого экземпляра "независимо от того, являются ли они
final
. - локальными переменными и параметрами, тоже могут быть
final
, и они не" занимают память на экземпляр "
Может ли это предположение быть сделано компилятором, если переменные final
инициализируются в самом их объявлении и выделяют ему память только один раз, потому что, очевидно, каждый созданный экземпляр будет иметь то же значение для этого финалапеременная.Достаточно ли уместен компилятор для такой оптимизации?
Учтите это
public class Test
public static test(final int val) {
System.out.println(val);
}
}
Теперь val
равно final
, но его значение зависит от того, как вы называете test
метод.Это не известно во время (javac
) компиляции, и обычно оно также не известно компилятору JIT.Действительно, предполагая, что test
вызывается с разными параметрами, вы не можете напрямую оптимизировать ячейку памяти val
.
То же самое относится к каждому случаю, кроме static final
переменных, которые квалифицируются как компиляцияпостоянные времени (согласно определению JLS).
Теоретически возможно, что JIT-компилятор мог видеть, что Test.test
вызывается только с одним и тем же постоянным значением, и встроить это значение в собственный код, чтобы не требовалась ячейка памяти.Однако такая оптимизация имеет минимальный выигрыш в производительности и вряд ли будет применима в реальном коде.Поэтому я сомневаюсь, что его реализация стоит .
(Более вероятно, что val
будет оптимизировано, поскольку тело test
встроено в его сайт вызова.Это более общая оптимизация, которая определенно стоит того, что может позволить оптимизатору глазка сделать вывод, что val
не требуется во встроенном коде.)