Подтвердить что ты не робот

Почему в нем говорится, что "Нельзя ссылаться на не конечную переменную я внутри внутреннего класса, определенного другим методом"?

У меня есть кнопка для прослушивания кнопок и в методе onCreate() у меня есть локальная переменная типа

 onCreate() {

 super.onCreate();

 int i = 10;

 Button button = (Button)findViewById(R.id.button);

 button.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            i++;
        }   
    });

Почему java просит меня сделать окончательный?

4b9b3361

Ответ 1

Когда метод onCreate() вернется, ваша локальная переменная будет очищена из стека, поэтому они больше не будут существовать. Но анонимный объект класса new View.OnClickListener() ссылается на эти переменные. Из-за этого неправильное поведение, поэтому java не позволяет вам это делать.

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

Ответ 2

Ваш анонимный внутренний класс ссылается на свою охватывающую область, беря копии локальных переменных - если вы хотите изменить значение int в анонимном внутреннем классе, вам нужно сделать хакерство:

final int[] arr = new int[1];
arr[0] = 10;
Button button = (Button)findViewById(R.id.button);

button.setOnClickListener(new View.OnClickListener() {
  arr[0]++;
}

Ответ 3

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

Параметры:

  • Вместо этого сделайте переменную экземпляра внешнего класса
  • Вместо этого сделайте переменную экземпляра анонимного внутреннего класса
  • Используйте обертку - например. одноэлементный массив, AtomicInteger или что-то вроде этого

Я бы предпочел бы второй вариант, если мне не понадобилось i в любом месте. Если честно, я считаю, что третий вариант - это немного неприятный хак.

Ответ 4

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

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

Так как ваша цель состоит в том, чтобы иметь инкрементирующее целое число, и только ссылка должна быть окончательной (сам объект не должен быть неизменным), вы можете объявить final AtomicInteger i, а затем увеличивать его, как вы хотите, от обратного вызова.

Ответ 5

Поскольку вам нужно увеличивать переменную i, вы не можете сделать ее окончательной. Вместо этого вы можете сделать его членом класса.