Kompilator automatycznie generuje konstruktor dla twojej anonimowej klasy wewnętrznej i przekazuje lokalną zmienną do tego konstruktora.
Konstruktor zapisuje tę wartość w zmiennej klasy (pole) o nazwie i
, która będzie używana wewnątrz "zamknięcia".
Dlaczego musi być ostateczny? Więc przyjrzyjmy się sytuacji w przypadku gdy nie jest:
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
}
}
W sytuacji A pole i
z Action
musi również zostać zmieniony, załóżmy to możliwe: potrzebuje odniesienie do obiektu Action
.
Załóżmy, że w sytuacji B ten przypadek Action
jest zbierany śmieci.
Teraz w sytuacji C: potrzebuje instancji Action
, aby zaktualizować zmienną klasy, ale jej wartość to GCed. Musi "wiedzieć", że jest GCed, ale to jest trudne.
Aby ułatwić wdrażanie maszyny wirtualnej, projektanci języka Java powiedzieli, że powinna ona być ostateczna, tak aby maszyna wirtualna nie potrzebowała sposobu sprawdzenia, czy obiekt zniknął, i zagwarantować, że zmienna nie jest zmodyfikowane i że maszyna wirtualna lub kompilator nie musi utrzymywać odniesienia do wszystkich zastosowań zmiennej wewnątrz anonimowych klas wewnętrznych i ich instancji.
W rzeczywistości zmienna syntezowana, która zawiera kopię zmiennej, nie ma nazwy i. W zależności od wersji używanego kompilatora to "$ i" lub "+ i". –