Иерархия внутренних классов в Java - PullRequest
7 голосов
/ 12 июля 2011

Я использую иерархию внутренних классов для представления некоторых данных в приложении, и я столкнулся с сообщением об ошибке, которое я просто не понимаю.Мой код можно свести к следующему минимальному примеру:

public class A {
    public class B extends A {}
    public class C extends B {}
}

Javac (и, конечно, моя IDE) не может скомпилировать код со следующим сообщением об ошибке:

A.java:3: cannot reference this before supertype constructor has been called
    public class C extends B {}
           ^
1 error

Ithis нигде не писал.Нет больше кода, чем указано выше, поэтому я предполагаю, что javac сгенерировал что-то, связанное с внутренним классом.

Я нашел другой способ представления моих данных, поэтому меня просто интересует хорошее объяснение того, почему этоне компилируется.

Ответы [ 3 ]

8 голосов
/ 12 июля 2011

Вам нужен экземпляр внешнего класса, чтобы создать экземпляр внутреннего класса, например, new Outer().new Inner();

Чтобы расширить внутренний класс (родительский внутренний класс) другим внутренним классом (дочерним внутренним классом), нельзя вызвать конструктор «родительского внутреннего класса», поскольку там нет экземпляра «внешнего класса».

Попробуй вот так,

public class A{        
    public class B extends A {
        B() { }  
    }    

    public class C extends B {
        C() { 
            new A().super();  
        }  
    }    

    public static void main(String args[])  {

    }      
}

Аналогичный вопрос: Странная ситуация для «не может ссылаться на это до вызова конструктора супертипа»

2 голосов
/ 12 июля 2011

Другой постер правильный, но как исправить?Просто сделайте ваш класс static:

public class A {
    public static class B extends A {}
    public static class C extends B {}
}

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

1 голос
/ 12 июля 2011

Ваш код компилируется под Java 7.

Следующий обходной путь компилируется под Java 6.

    public class C extends B
    {
        public C()
        {
            A.this.super();
        }
    }

@ Ссылка Саугока на предыдущий вопрос цитирует объяснение Джошуа. В основном он утверждал, что, поскольку C является подклассом A, C наследует членов A как членов C. Следовательно, B также является членом C. (Например, допустим литерал класса C.B.class.) Поэтому он утверждает, что C.this является включающим экземпляром для B's super(), поэтому C(){super();} на самом деле C(){C.this.super();}. Так как C.this не может быть оценен перед супер-конструктором, то это ошибка.

Однако, похоже, это не гарантируется языковой спецификацией. Смотрите # 8.1.3. Поскольку B не является немедленно лексическим , заключенным в C, B не является прямым внутренним классом C, нет никаких оснований утверждать, что прямой экземпляр B должен быть экземпляром C.

Нам нужно передать B() экземпляр A. Это правда, что C.this является экземпляром A (попробуйте этот код: new C().new B().new C().new B();), поэтому он может быть кандидатом. Есть еще один кандидат, A.this. A.this доступен и готов к использованию (он передается в качестве скрытого параметра в C()).

Согласно javap, javac 7 компилирует код в

class B
    private A this$0;
    B( A a )
        this$0 = a;
        super(); // A()

class C extends B
    private A this$0;
    C( A a )
        this$0 = a;
        super( a ); // B(A)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...