2013-08-14 3 views
4

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

private void testMethod (ListField<BeanModel> listField){ 

    final ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>(); 
    listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() { 

      @Override 
      public void handleEvent(ListViewEvent<BeanModel> be) { 
       loader.load(); 
      } 
      }); 
} 

Однако, если загрузчик был поле класса, это не было бы необходимо объявить его как окончательный:

public class testClass{ 

    private ListLoader<BeanModel> loader = new PagedListLoader<BeanModel>(); 

    private void testMethod (ListField<BeanModel> listField){ 
     listField.addListener(Events.Attach, new Listener<ListViewEvent<BeanModel>>() { 

        @Override 
        public void handleEvent(ListViewEvent<BeanModel> be) { 
         loader.load(); 
        } 
        }); 

     //Could I modify loader's reference here, before the method executes? 
     //loader = null; 
     } 
} 

Кто-нибудь знает причину, почему они гарантируют локальные переменные не изменяются, когда они 're accessed, но не делают это для полей классов?

+0

@jlordo. Не совсем. Это сообщение не говорит о полях, а только о локальных переменных. –

+0

Тот же принцип применяется.Это (анонимный) внутренний класс, который ссылается на экземпляр внешнего окружения и, следовательно, может получить доступ к его полям. – jlordo

+0

еще один здесь http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen – kaos

ответ

3

Локальная переменная выделяется в стеке, и после она будет выпадать из области. Создание окончательной переменной гарантирует, что можно просто передать ссылку на анонимный класс. Если это не было окончательным, позднее назначение в testMethod() могло бы изменить значение позже с запутанными результатами. (Пользователь может ожидать, что используется позднее назначенное значение, но это было бы невозможно).

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

+0

Но что, если содержимое поля изменилось за это время? –

+0

@ AminAbu-Taleb Поскольку доступ проходит через родительскую ссылку, внутренний класс всегда может использовать последнее значение. – kiheru

+0

Вот что я искал. –

1

Посмотрите на Lambdas и Conjures в java.

У анонимного внутреннего класса нет информации об этом - вы должны указать, что он является окончательным, чтобы вы могли гарантировать его существование.

Это может быть связано с природой ListLoader, но я не ознакомлен с использованием этой библиотеки.

Надеюсь, я указал вам в правильном направлении.

1

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

8

Accroding для Java docs

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

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

+0

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

+0

Подумайте, что произойдет, если локальные переменные выйдут из сферы действия? Например, предположим, что вы представили несколько будущих задач, используя некоторые локальные переменные, которые начинаются через 2 часа, а текущий метод завершен. Как вы вернетесь к тем первоначальным значениям, которые ушли из стека? –

Смежные вопросы

 Смежные вопросы