Компилятор автоматически генерирует конструктор для вашего анонимного внутреннего класса и передает вашу локальную переменную в этот конструктор.
Конструктор сохраняет это значение в переменной класса (поле), также называемой i
, которая будет использоваться внутри «замыкания».
Почему это должно быть окончательным? Что ж, давайте рассмотрим ситуацию, в которой это не так:
public class A {
public void method() {
int i = 0; // note: this is WRONG code
doStuff(new Action() {
public void doAction() {
Console.printf(i); // or whatever
}
});
i = 4; // A
// B
i = 5; // C
}
}
В ситуации A поле i
из Action
также необходимо изменить, давайте предположим, что это возможно: ему нужна ссылка на объект Action
.
Предположим, что в ситуации B этот экземпляр Action
является сборщиком мусора.
Теперь в ситуации C: ему требуется экземпляр Action
для обновления переменной класса, но значение GCed. Нужно «знать», что это GCed, но это сложно.
Таким образом, чтобы упростить реализацию виртуальной машины, разработчики языка Java сказали, что она должна быть окончательной, чтобы у виртуальной машины не было способа проверить, не исчез ли объект, и гарантировать, что переменная не была изменена. и что ВМ или компилятору не нужно хранить ссылки на все случаи использования переменной внутри анонимных внутренних классов и их экземпляров.