Когда создается анонимный внутренний класс, значения всех переменных, используемых в нем, копируются. Поэтому, если внутренний класс попытается изменить значение переменной, то не будет видимым. Например, предположим, что это действительно:
int a = 7;
Runnable r = new Runnable() {
public void run() {
a = 5;
}
};
r.run();
System.out.println(a);
Вы можете ожидать, что напечатает 5 (что на самом деле в C #). Но поскольку была взята только копия , на самом деле было бы напечатано 7 ... если бы это было разрешено, без больших изменений.
Конечно, Java можно было бы изменить, чтобы он действительно захватывал переменную вместо ее значения (как C # для анонимных функций). Для этого необходимо автоматически создать дополнительный класс для хранения «локальных» переменных и сделать так, чтобы метод и анонимный внутренний класс совместно использовали экземпляр этого дополнительного класса. Это сделало бы анонимные внутренние классы более мощными , но, возможно, труднее для понимания. C # решил пойти по пути мощности, но сложности; Ява придерживалась ограничительного, но простого подхода.
(Использование массива вместо пользовательского класса допустимо для одной переменной, но становится более расточительным, когда задействовано несколько переменных - вам не нужно создавать объект-оболочку для каждой переменной , если вы можете помочь.)
Обратите внимание, что в подходе захвата переменной есть существенные сложности, по крайней мере, с использованием правил C #. Например:
List<Runnable> runnables = new ArrayList<Runnable>();
int outer = 0;
for (int i = 0; i < 10; i++) {
int inner = 0;
runnables.add(new Runnable() {
public void run() {
outer++;
inner++;
}
});
}
Сколько "внутренних" переменных создано? Один для каждого экземпляра цикла или один общий? По сути, прицелы делают жизнь такой сложной. Возможно, но сложно.