Есть пример кода: 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?
Ответ Это ограничение, которое ввели разработчики спецификации: при создании анонимного класса происходит захват объектов по значению, а не по ссылке. В анонимном классе создаются закрытые поля, в которые копируются значения переданных переменных. То есть по сути реализована эмуляция замыканий. Добавление модификатора 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?