локальные внутренние методы метода, обращающиеся к локальным переменным метода - PullRequest
2 голосов
/ 04 мая 2010

Привет, я просматривал книгу SCJP о внутренних классах и нашел это утверждение, оно выглядит примерно так.

Локальный класс метода может ссылаться только на локальные переменные, помеченные final

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

Ответы [ 2 ]

6 голосов
/ 04 мая 2010

Причина в том, что при создании экземпляра локального класса метода все локальные переменные метода, на которые он ссылается, фактически копируются в него компилятором. Вот почему доступны только final переменные. Переменная или ссылка final является неизменной, поэтому она синхронизируется со своей копией в локальном объекте метода. Если бы это было не так, исходное значение / ссылка могли бы быть изменены после создания локального класса метода, что привело бы к запутанному поведению и тонким ошибкам.

Рассмотрим этот пример из бюллетеня JavaSpecialist №. 25

public class Access1 {
  public void f() {
    final int i = 3;
    Runnable runnable = new Runnable() {
    public void run() {
      System.out.println(i);
    }
    };
  }
}

Компилятор превращает внутренний класс в это:

class Access1$1 implements Runnable {
  Access1$1(Access1 access1) {
    this$0 = access1;
  }
  public void run() {
    System.out.println(3);
  }
  private final Access1 this$0;
}

Поскольку значение i является окончательным, компилятор может "встроить" его во внутренний класс.

3 голосов
/ 04 мая 2010

На мой взгляд, доступ к локальным переменным из локальных классов метода (например, анонимного класса) является рискованным делом. Это разрешено компилятором, но требует хорошего понимания происходящего.

Когда создается экземпляр внутреннего класса, все ссылки на локальные переменные, которые он использует, копируются и передаются как неявные параметры конструктора (проверьте байт-код). На самом деле компилятор мог бы разрешить делать ссылки не окончательными, но это могло бы сбить с толку, поскольку неясно, что произойдет, если метод изменяет ссылки после создания экземпляра.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...