#java
Есть пример кода: public static void main(String[] args){ int a=5; new Thread(new Runnable(){ @Override public void run() { System.out.println(a); } }).start(); } Нужно использовать переменную a в анонимном классе, компилятор говорит объявить её как final. Почему она должна быть final?
Ответы
Ответ 1
Это ограничение, которое ввели разработчики спецификации: при создании анонимного класса происходит захват объектов по значению, а не по ссылке. В анонимном классе создаются закрытые поля, в которые копируются значения переданных переменных. То есть по сути реализована эмуляция замыканий. Добавление модификатора final как бы говорит программисту о том, что при использовании такого рода замыканий не будут наблюдаться побочные эффекты (представьте, что вы передали в созданный объект анонимного класса переменную, а затем изменили её "снаружи" - вы в праве ожидать, что это изменение отразится и внутри замыкания, но это не так в силу пресловутой эмуляции; однако изменение внутреннего состояния mutable объектов будет видно и там и там). Для реализации полноценных замыканий необходимо расширять жизненный цикл захватываемых объектов (это касается объектов, расположенных в стеке, которые при выходе из области видимости, в которой они объявлены, уничтожаются). Почему это не реализовано до сих пор? Для такого рода реализации необходимо внести серьезное изменение в саму архитектуру JVM. Такого рода изменения достаточно сложно внедрить по определенным причинам: потребуется много усилий для внесения изменений не только со стороны Oracle, но и со стороны сторонних разработчиков (дебаггеры, обфускаторы, IDE, компиляторы и т.д.). Внесение такого изменения может привести к утрате обратной совместимости, что отразится на множестве уже существующих приложений. Изменение может отразиться на других языках/платформах, завязанных на среде JVM. В Java 8 ввели понятие effectively final - это переменные, которые не имеют модификатора final, но могут использоваться в анонимных классах и лямбда-выражениях. Переменная будет effectively final, если после её определения она не изменяется. Соответственно на Java 8 ваш код будет скомпилирован. Дополнительные ссылки для более подробного ознакомления: Accessing Members of an Enclosing Class, Why are only final variables accessible in anonymous class? Does Java 8 Support Closures?Ответ 2
Ваш код создаёт поток, поток запускается на выполнение, а вызвавшая поток функция (в данном случае main) может завершиться. При завершении функции все её локальные переменные, в том числе и i исчезнут, выделенная под них память возвратится системе. Следовательно, поток не должен иметь доступ к локальным переменным. Но! Если у переменной Вы укажете квалификатор final, то Вы, фактически, говорите компилятору, что это не переменная, а константа. Компилятор будет уверен, что после инициализации эта константа не изменится, поэтому со спокойной совестью вместо прямого обращения к переменной поставит внутри кода потока её копию.
Комментариев нет:
Отправить комментарий