Вопрос о локальной финальной переменной в Java

У меня есть следующий код:

public class BookLib {
    void f() {
        final int x = 5; // Line 1
        class MyCLass {
            void print() {
                System.out.println(x);
            }
        }
    }
}

Я не понимаю, почему следует использовать окончательную переменную в этом случае (строка 1)?

4 ответа

Решение

Вы создали внутренний класс здесь. Поскольку время жизни объектов этого класса потенциально может быть намного больше времени выполнения вызова метода (т. Е. Объект может существовать еще долго после возврата метода), ему необходимо "сохранить" состояние локальных переменных, которые он может получить доступ.

Это сохранение выполняется путем создания (невидимой, синтетической) копии внутри внутреннего класса и автоматической замены всех ссылок на локальную переменную ссылками на эту копию. Это может привести к странным эффектам, когда локальная переменная была изменена после создания объекта внутреннего класса.

Чтобы избежать этого, существует требование, чтобы все локальные переменные, к которым вы обращаетесь таким образом, были final: это гарантирует, что существует только одно возможное значение для локальной переменной, и никаких несоответствий не наблюдается.

Это конкретное правило можно найти в §8.1.3 Внутренние классы и включающие экземпляры JLS:

Любая локальная переменная, формальный параметр метода или параметр обработчика исключений, используемые, но не объявленные во внутреннем классе, должны быть объявлены как окончательные. Любая локальная переменная, используемая, но не объявленная во внутреннем классе, должна быть обязательно назначена (§16) перед телом внутреннего класса.

Здесь вы создаете внутренний класс. Чтобы получить доступ к контексту выполнения, ссылки на переменные должны оставаться неизменными, в противном случае наблюдается поведение ошибки. Чтобы гарантировать это, вы должны объявить вашу переменную final: таким образом, ее нельзя изменить.

Смотрите подробное объяснение здесь.

От Кэти Сьерра Scjp Book

Локальные переменные метода живут в стеке и существуют только в течение времени жизни метода. Мы уже знаем, что область действия локальной переменной ограничена методом, в котором объявлена ​​переменная. Когда метод заканчивается, фрейм стека уничтожается, а переменная становится историей. Но даже после завершения метода внутренний объект класса, созданный в нем, может оставаться в куче, если, например, ссылка на него была передана в некоторый другой код, а затем сохранена в переменной экземпляра. Поскольку локальные переменные не гарантируются живыми до тех пор, пока объект внутреннего класса метода локальный, объект внутреннего класса не может их использовать. Если только локальные переменные не помечены как окончательные!

Таким образом, у вас есть локальная конечная переменная и метод локального внутреннего класса. Внутренний класс локального метода не может использовать неконечные переменные, объявленные в методе (включая параметры).

Чтобы углубиться в это: метод локального внутреннего класса может быть создан только внутри метода, в котором этот класс определен. Локальные переменные живут в стеке в течение всего времени жизни метода. Когда метод заканчивается, локальные переменные исчезают, однако созданный объект внутреннего класса все еще живет.

Это вопрос жизни / объема.

Другие вопросы по тегам