Что точно происходит, когда у Вас есть окончательные значения и внутренние классы в методе?

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

public void method() {
    final EventHandler handle = someReference;

    Thread thread = new Thread() {
        public void run() {
            handle.onEvent();
        }
    };

    thread.start();
}

Править: Просто поймите, что мой вопрос точно не указывал на то, что я хотел знать. Это больше, "как" это работает скорее затем "почему".

11
задан HoLyVieR 26 June 2010 в 20:36
поделиться

4 ответа

Вы можете заметить, что происходит внизу, просто декомпилировав внутренний класс. Вот краткий пример:

После компиляции этого фрагмента кода:

public class Test {

 public void method() {
     final Object handle = new Object();

     Thread thread = new Thread() {
         public void run() {
             handle.toString();
         }
     };

     thread.start();
 }
}

вы получите Test.class для Test.java и Test $ 1.class для внутреннего класса в Test.java . После декомпиляции Test $ 1.class вы увидите следующее:

class Test$1 extends Thread
{
  final Test this$0;
  private final Object val$handle;

  public void run()
  {
    this.val$handle.toString();
  }
}

Как видите, вместо переменной handle есть this.val $ handle . Это означает, что дескриптор копируется как поле val $ handle во внутренний класс. И это будет работать правильно, только если дескриптор никогда не изменится - что в Java означает, что он должен быть final .

Вы также можете заметить, что у внутреннего класса есть поле this $ 0 , которое является ссылкой на внешний класс. Это, в свою очередь, показывает, как нестатические внутренние классы могут взаимодействовать с внешними классами.

7
ответ дан 3 December 2019 в 03:51
поделиться

Вот более подробное объяснение того, КАК это работает: http://techtracer.com/2008/04/14/mystery-of-accessibility-in-local-inner-classes/

9
ответ дан 3 December 2019 в 03:51
поделиться

Ни один метод не может получить доступ к локальным переменным других методов. Сюда входят методы анонимных классов, как в вашем примере. То есть метод run в анонимном классе Thread не может получить доступ к локальной переменной метода method () .

Запись final перед локальной переменной - это способ для вас, как программиста, сообщить компилятору, что переменная на самом деле может рассматриваться как значение. Поскольку эта переменная (считываемое значение!) Не изменится, можно получить к ней доступ другими методами.

8
ответ дан 3 December 2019 в 03:51
поделиться

Этот внутренний класс транслируется в код, подобный следующему:

class InnerClass extends Thread {
    private EventHandler handle;

    public InnerClass(EventHandler handle) {
        this.handle = handle;
    }

    public void run() {
        handle.onEvent();
    }
}

...

EventHandler handle = someReference;
Thread thread = new InnerClass(handle);
thread.start();

Поскольку внутреннему классу фактически передается копия последней переменной, он не может вносить в нее какие-либо изменения, которые были бы видны во внешнем классе. Чтобы запретить даже попытки внести изменения в этот параметр, разрешен доступ только к конечным переменным во внутренних классах.

2
ответ дан 3 December 2019 в 03:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: