Переменная, доступная изнутри внутреннего класса, должна быть объявлена ​​окончательной [дубликат]

Вы можете рассмотреть стороннюю службу электронной почты, которая обрабатывает проблемы с доставкой:

  • Точная цель
  • Вертикальный ответ
  • Постоянный контакт
  • Монитор кампании
  • Эмма
  • Обратный путь
  • IntelliContact
  • SilverPop
81
задан Suragch 5 December 2016 в 05:37
поделиться

5 ответов

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

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

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

39
ответ дан Brendan L 15 August 2018 в 20:15
поделиться

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

92
ответ дан Kevin Zhao 15 August 2018 в 20:15
поделиться
  • 1
    @KevinZhao Являются ли глобальные переменные окончательными после их инициализации? – the_prole 11 October 2015 в 22:55
  • 2
    @the_prole Я думаю, что вы можете использовать final на Java, но я не уверен, что вы можете использовать его при создании приложения для Android, поэтому Googling это может быть хорошей идеей :-) – Kevin Zhao 12 October 2015 в 20:15
  • 3
    Оглядываясь назад, использование глобальных переменных - плохая идея, если их можно избежать, если вы не новичок, и в этом случае чрезмерное усложнение вашей программы с помощью глобальных переменных является хорошим опытом обучения. Здесь - хорошая статья, объясняющая, почему глобальные переменные - плохая идея. – the_prole 21 November 2015 в 23:08

Как сказал @Veger, вы можете сделать его final, чтобы переменная могла использоваться во внутреннем классе.

final ViewPager pager = (ViewPager) findViewById(R.id.fieldspager);

Я назвал его pager, а не mPager, потому что вы используют его как локальную переменную в методе onCreate. Префикс m зарезервирован для переменных класса (т.е. переменных, объявленных в начале класса и доступных для всех методов класса).

Если вам действительно нужна переменная-член класса, он не работает, чтобы сделать его окончательным, потому что вы не можете использовать findViewById, чтобы установить его значение до onCreate. Решение состоит в том, чтобы не использовать анонимный внутренний класс. Таким образом, переменная mPager не обязательно должна быть объявлена ​​окончательной и может использоваться во всем классе.

public class MainActivity extends AppCompatActivity {

    private ViewPager mPager;
    private Button mButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...

        mPager = (ViewPager) findViewById(R.id.fieldspager);

        // ...

        mButton.setOnClickListener(myButtonClickHandler);
    }


    View.OnClickListener myButtonClickHandler = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mPager.setCurrentItem(2, true);
        }
    };
}
3
ответ дан Suragch 15 August 2018 в 20:15
поделиться

Вот забавный ответ.

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

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

final int[] tapCount = {0};

addSiteButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
       tapCount[0]++;
    }

});
2
ответ дан the_new_mr 15 August 2018 в 20:15
поделиться
  • 1
    В приведенном выше случае вы не меняете ссылочный объект, а изменяете содержимое внутри массива. ссылка имеет приятное объяснение. – Abilash 17 July 2018 в 05:54
  • 2
    Да, я знаю. Просто похоже на взломать проблему. Спасибо за ваш комментарий, разъясняющий это для других. – the_new_mr 17 July 2018 в 13:42
  • 3
    хочу, чтобы я мог haha ​​ реагировать – MrClan 27 July 2018 в 17:43

Ошибка говорит об этом, измените:

ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);

на

final ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);
38
ответ дан Veger 15 August 2018 в 20:15
поделиться
  • 1
    Причина: если два метода видят одну и ту же локальную переменную, Java хочет, чтобы вы клялись, что вы ее не измените - final, в Java говорят. Вместе с отсутствием параметров ссылки, это правило гарантирует, что locals назначаются только в том методе, к которому они принадлежат. Таким образом, код более читабельен. – ignis 20 January 2013 в 17:21
  • 2
    @ignis Я получаю ошибку NullPointerException на addSiteButton.setOnClickListener(new View.OnClickListener() {, есть ли у вас какие-либо идеи, почему это произойдет? – PhDeOliveira 21 January 2013 в 18:52
  • 3
    @PhDeOliveira NPE обычно бросается, когда вы вызываете метод для переменной, которая содержит null. Вероятно, findViewById возвращает null. Я не могу сказать больше, не будучи программистом на Android; Я советую вам открыть отдельный вопрос. Конечно, это не имеет ничего общего с внутренними классами, final, et similia . – ignis 21 January 2013 в 23:02
Другие вопросы по тегам:

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