Le compilateur génère automatiquement un constructeur pour votre classe interne anonyme et transmet votre variable locale à ce constructeur.
Le constructeur enregistre cette valeur dans une variable de classe (un champ), également appelée i
, qui sera utilisée dans la "fermeture".
Pourquoi cela doit-il être définitif? Eh bien, nous allons explorer la situation où il 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
}
}
Dans la situation A champ i
de Action
doit également être changé, supposons que cela est possible: il a besoin de la référence à l'objet Action
.
Supposons que dans la situation B, cette instance de Action
est récupérée à la poubelle.
Maintenant dans la situation C: il a besoin d'une instance de Action
pour mettre à jour sa variable de classe, mais la valeur est GCed. Il doit "savoir" que c'est GCed, mais c'est difficile.Donc, pour simplifier l'implémentation de la machine virtuelle, les concepteurs de langage Java ont dit qu'elle devrait être finale de sorte que la machine virtuelle n'ait pas besoin de vérifier si un objet est parti, et garantir que la variable n'est pas modifié, et que la machine virtuelle ou le compilateur n'a pas à conserver la référence de tous les usages de la variable dans les classes internes anonymes et leurs instances.
En fait, la variable synthétisée qui contient une copie de la variable n'est pas nommée i. Selon la version du compilateur que vous utilisez, "$ i" ou "+ i". –