Il compilatore genera automaticamente un costruttore per la classe interna anonima e passa la variabile locale in questo costruttore.
Il costruttore salva questo valore in una variabile di classe (un campo), anch'essa denominata i
, che verrà utilizzata all'interno della "chiusura".
Perché deve essere definitivo? Bene cerchiamo di esplorare la situazione in cui non è:
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
}
}
Nella situazione Un campo i
di Action
ha anche bisogno di essere cambiato, supponiamo che questo è possibile: ha bisogno del riferimento all'oggetto Action
.
Si supponga che nella situazione B questa istanza di Action
sia Garbage-Collected.
Ora nella situazione C: ha bisogno di un'istanza di Action
per aggiornare la sua variabile di classe, ma il valore è GCed. Ha bisogno di "sapere" che è GCed, ma è difficile.
Quindi per semplificare l'implementazione della VM, i progettisti del linguaggio Java hanno detto che dovrebbe essere definitivo in modo tale che la VM non abbia bisogno di un modo per verificare se un oggetto è andato e garantire che la variabile non sia modificato, e che la VM o il compilatore non deve mantenere il riferimento di tutti gli usi della variabile all'interno di classi interne anonime e delle loro istanze.
In realtà, la variabile sintetizzata che contiene una copia della variabile non è denominata i. A seconda della versione del compilatore che stai usando, è "$ i" o "+ i". –