Иерархия внутренних классов в Java

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

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

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

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

3 ответов


вам нужен экземпляр внешнего класса для создания экземпляра внутреннего класса i.e что-то вроде 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[])  {

    }      
}

аналогичный вопрос : нечетная ситуация для " не может ссылаться на это, прежде чем конструктор supertype назывался"


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

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

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


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

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

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

@saugok ссылка на предыдущий вопрос цитирует объяснение Джошуа. В основном он утверждал, что, поскольку 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's прямой заключительный экземпляр должен быть экземпляром 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;
    B( A a )
        this = a;
        super(); // A()

class C extends B
    private A this;
    C( A a )
        this = a;
        super( a ); // B(A)