Когда внутренние классы были добавлены в Java в версии 1.1 языка, они изначально были определены как преобразование в код, совместимый с 1.0. Если вы посмотрите на пример этого преобразования, я думаю, он сделает более понятным, как на самом деле работает внутренний класс.
Рассмотрим код из ответа Яна Робертса:
public class Foo {
int val;
public Foo(int v) { val = v; }
class Bar {
public void printVal() {
System.out.println(val);
}
}
public Bar createBar() {
return new Bar();
}
}
При преобразовании в код, совместимый с 1.0, этот внутренний класс Barстанет примерно таким:
class Foo$Bar {
private Foo this$0;
Foo$Bar(Foo outerThis) {
this.this$0 = outerThis;
}
public void printVal() {
System.out.println(this$0.val);
}
}
Имя внутреннего класса имеет префикс с именем внешнего класса, чтобы сделать его уникальным. this$0Добавляется скрытый частный член, который содержит копию внешнего this. И создается скрытый конструктор для инициализации этого члена.
А если посмотреть на createBarметод, то он трансформируется примерно в это:
public Foo$Bar createBar() {
return new Foo$Bar(this);
}
Итак, давайте посмотрим, что произойдет, когда вы выполните следующий код.
Foo f = new Foo(5);
Foo.Bar b = f.createBar();
b.printVal();
Сначала мы создаем экземпляр Fooи инициализируем valчлен до 5 (т.е. f.val = 5).
Затем мы вызываем f.createBar(), который создает экземпляр Foo$Barи инициализирует this$0член значением, thisпереданным из createBar(т.е. b.this$0 = f).
Наконец , мы называем , b.printVal()который пытается напечатать b.this$0.valчто f.valчто 5.
Теперь это было обычное создание внутреннего класса. Давайте посмотрим, что происходит при создании экземпляра Barизвне Foo.
Foo f = new Foo(5);
Foo.Bar b = f.new Bar();
b.printVal();
Снова применив наше преобразование 1.0, эта вторая строка станет примерно такой:
Foo$Bar b = new Foo$Bar(f);
Это почти идентично f.createBar()звонку. Мы снова создаем экземпляр Foo$Barи инициализируем this$0член для f. Итак, снова b.this$0 = f.
И еще раз , когда вы звоните b.printVal(), вы печатаете , b.thi$0.valкоторый , f.valкоторый является 5.
Важно помнить, что у внутреннего класса есть скрытый член, содержащий копию thisвнешнего класса. Когда вы создаете экземпляр внутреннего класса из внешнего класса, он неявно инициализируется текущим значением this. Когда вы создаете экземпляр внутреннего класса вне внешнего класса, вы явно указываете, какой экземпляр внешнего класса использовать, через префикс newключевого слова.