Часто лучший способ узнать, как компилятор Java что-то делает, - это скомпилировать класс и затем запустить его через Jad (JAva Decompiler).В этом случае создается впечатление, что javac просто создает дополнительную переменную в анонимном внутреннем классе с именем «val $ o» и инициализирует ее в статическом инициализаторе.Видя это преобразование, становится понятнее, почему Java требует, чтобы вы сделали переменную final, прежде чем использовать ее в анонимном внутреннем классе.Без требования две переменные могут иметь разные значения во время выполнения.Кроме того, это на самом деле ничем не отличается от механизма, который Java использует, чтобы разрешить всем внутренним классам (анонимным или именованным) доступ к содержащему их классу.Вы можете видеть, что внутренний класс содержит ссылку на переменную this этого класса с именем "this $ 0".
Я скомпилировал более простой пример:
public class Outer {
public void outerMethod() {
final Object o = "fromOuter";
new Object() {
public void innerMethod() {
System.out.println(o);
}
}.innerMethod();
}
}
и получил это от другогоконец:
public class Outer {
public Outer()
{
}
public void outerMethod()
{
final Object o = "fromOuter";
(new Object() {
public void innerMethod()
{
System.out.println(o);
}
final Outer this$0;
private final Object val$o;
{
this$0 = Outer.this;
o = obj;
super();
}
}).innerMethod();
}
}