Статический (вложенный) класс работает точно так же, как класс верхнего уровня. Единственное отличие состоит в том, что у его имени есть другое имя класса с префиксом. (Если вы посмотрите на скомпилированные файлы .class, то увидите, что вы получите что-то вроде «Outer $ Nested.class» для класса с именем Nested, вложенного в класс с именем Outer.)
Внутренний класс имеет скрытое поле, которое является ссылкой на содержащий экземпляр его внешнего класса. Когда вы пишете:
class Outer {
final int x;
class Nested {
int y;
Nested(int y) {
this.y = y;
}
int bar() {
return x + y;
}
}
void foo() {
Nested n = new Nested(5);
}
}
Это как если бы вы написали:
class Outer {
final int x;
static class Nested {
Outer outer;
int y;
Nested(Outer outer, int y) {
this.outer = outer;
this.y = y;
}
int bar() {
return outer.x + y;
}
}
void foo() {
Nested n = new Nested(this, 5);
}
}
Имя этого скрытого поля (которое я назвал здесь "внешним") скрыто
к вам, хотя вы можете обратиться к нему, сказав Outer.this
внутри
внутренний класс (где Outer
- это имя вашего внешнего класса, конечно).
Также обратите внимание, что когда метод во внутреннем классе ссылается на
что-то во внешнем классе, эта ссылка на самом деле через этот скрытый
ссылка на внешний класс.
Есть несколько дополнительных сложностей, связанных с тем, как управление доступом (например, private) работает с вложенными / внутренними классами, но это не влияет на вопрос «памяти», который вы задаете.