2016-03-04 4 views
11

У меня есть три классаИспользование супер() со ссылкой на Java

class WithInner { 
    class Inner {} 
} 

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

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

+0

Странный код еще компилирует ... – h22

+0

'wi = new WithInner();' создаст новый объект 'WithInner', но ничего не сделает с тем, который задан конструктору. –

+0

@ammoQ нет, он не смог бы скомпилировать.См. Мой ответ ниже. – davmac

ответ

8

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

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

wi.super(); 

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

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

wi.new WithInner.Inner() 

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

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

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

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

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

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

+0

Отличное объяснение. Надеюсь, этого достаточно, чтобы отговорить кого-либо от намеренного внедрения такого дизайна. – VGR

Смежные вопросы