Почему мой объект видит переменные, которые ему не были переданы в конструкторе? - PullRequest
3 голосов
/ 20 марта 2010

У меня есть следующий код. Что является «правильным» и что я не понимаю:

private static void updateGUI(final int i, final JLabel label) {
    SwingUtilities.invokeLater( 
        new Runnable() {
            public void run() {
                label.setText("You have " + i + " seconds.");
            }
        }
    );
}

Я создаю новый экземпляр класса Runnable, а затем в методе run этого экземпляра использую переменные label и i. Это работает, но я не понимаю, почему это работает. Почему рассматриваемый объект видит значения этих переменных.

Насколько я понимаю, код должен выглядеть так (и это неправильно):

private static void updateGUI(final int i, final JLabel label) {
    SwingUtilities.invokeLater(new Runnable(i,label) {

        public Runnable(int i, JLabel label) {
            this.i = i;
            this.label = label;
        }

        public void run() {
            label.setText("You have " + i + " seconds.");
        }

    });
}

Итак, я бы дал конструктору переменные i и label, чтобы объект мог получить к ним доступ ...

Кстати, в updateGUI я использую final перед i и label. Я думаю, что использовал final, потому что компилятор хотел этого. Но я не понимаю, почему.

Ответы [ 4 ]

4 голосов
/ 20 марта 2010

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

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

new Runnable() {
  { /* this code is executed */ }

  public void run() {
    // ...
  }
};

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

2 голосов
/ 20 марта 2010

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

2 голосов
/ 20 марта 2010

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

0 голосов
/ 20 марта 2010

Причина, по которой вы можете это сделать, - последнее ключевое слово. Это ссылка, объясняющая почему. http://en.wikipedia.org/wiki/Final_%28Java%29

...