El compilador genera automáticamente un constructor para su clase interna anónima, y pasa su variable local a este constructor.
El constructor guarda este valor en una variable de clase (un campo), también llamado i
, que se usará dentro del "cierre".
¿Por qué tiene que ser definitiva? Así que vamos a explorar la situación en donde no está:
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
}
}
En la situación A i
el campo de Action
también necesita ser cambiado, vamos a suponer que esto es posible: se necesita la referencia al objeto Action
.
Supongamos que en la situación B esta instancia de Action
es Basura-Recolectada.
Ahora en la situación C: necesita una instancia de Action
para actualizar su variable de clase, pero el valor es GCed. Necesita "saber" que está GCed, pero eso es difícil.
Para simplificar la implementación de la máquina virtual, los diseñadores del lenguaje Java han dicho que debería ser definitiva, de modo que la máquina virtual no necesita una forma de verificar si un objeto se ha ido y garantizar que la variable no sea modificado, y que la VM o compilador no tiene que mantener referencia de todos los usos de la variable dentro de las clases internas anónimas y sus instancias.
En realidad, la variable sintetizada que contiene una copia de la variable no se llama i. Dependiendo de la versión del compilador que esté usando, es "$ i" o "+ i". –