Конечные переменные занимают память для каждого экземпляра? - PullRequest
0 голосов
/ 04 октября 2018

Я прочитал другие вопросы-ответы, касающиеся переменных конечного экземпляра, и я понял, что нестатические переменные конечного экземпляра создаются в куче для каждого экземпляра класса , но в java - полная ссылка Герберта Шильдта сказано, что:

Переменные, объявленные как final, не занимают память для каждого экземпляра. Таким образом, финальная переменная по существуконстанта

Что правильно?

1 Ответ

0 голосов
/ 04 октября 2018

Первый оператор корректен ... хотя и ограничен 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 не требуется во встроенном коде.)

...