Использовать super() со ссылкой в ​​Java

У меня есть три класса

class WithInner {
   class Inner {}
}

public class InheritInner extends WithInner.Inner
{ //constructor
InheritInner(WithInner wi) {
    wi.super();
}
}

Этот пример взят из Eckel Thinking в Java. Я не понимаю, почему мы не можем называть wi = new WithInner(); вместо .super()? И при вызове wi.super() мы вызываем конструктор по умолчанию Object, не так ли?

Ответ 1

Внутренние классы поддерживают ссылку на внешний экземпляр (исключение составляют static внутренние классы). В этом случае экземпляр WithInner.Inner имеет ссылку на содержащий WithInner экземпляр. Эта ассоциация создается при создании экземпляра внутреннего класса.

Вы не можете создать экземпляр внутреннего класса без ссылки на внешний класс. Класс, который расширяет такой внутренний класс, также подразумевает такую ​​ссылку и должен делегировать внутреннему конструктору класса, чтобы установить связь. Синтаксис для этого показан в вашем примере:

wi.super();

Здесь super() по существу относится к конструктору суперкласса, то есть конструктору WithInner.Inner. Конструктор не принимает никаких параметров формально, но ему все еще нужна ссылка на внешний экземпляр (типа WithInner). Строка в целом по существу означает "вызвать конструктор суперкласса и связать с экземпляром wi".

Сравнение с синтаксисом для создания внутреннего класса с явной ассоциацией:

wi.new WithInner.Inner()

Да, это также действительный синтаксис. Однако это не часто встречается в дикой природе (поскольку внутренние экземпляры классов обычно создаются только из внешнего класса в любом случае, и в этом случае ассоциация неявно - в этом случае нет необходимости в этом синтаксисе, который явно предоставляет ассоциацию).

С конкретной ссылкой на ваш вопрос:

Не могу понять, почему мы не можем назвать wi = new WithInner(); вместо .super()?

Это не связывает созданный экземпляр WithInner с экземпляром внутреннего класса. Вы получите ошибку времени компиляции, потому что ваш конструктор InheritInner больше не будет явно вызывать синтезированный конструктор суперкласса, и его нельзя назвать неявным, потому что ему нужна ссылка внешнего экземпляра для ассоциации. Вероятно, проще всего рассматривать ссылку на внешний экземпляр как скрытый параметр для внутреннего конструктора классов (действительно, что он реализован под капотом).

И при вызове wi.super() мы вызываем конструктор по умолчанию Object, не так ли?

Нет, вы вызываете конструктор WithInner.Inner, у которого есть "скрытый" параметр для ссылки на внешний экземпляр; wi по существу передается конструктору WithInner.Inner в качестве значения скрытого параметра.