Не удается найти параметр типа, если он является внутренним классом подкласса в Java

Почему следующий код имеет ошибку компиляции:

Foo.java:

public abstract class Foo<T> {
    public abstract T getInner();
}

MyFoo.java:

public class MyFoo extends Foo<MyFooInner> {
    public static class MyFooInner {
    }
    public MyFooInner getInner() {
        return new MyFooInner();
    }
}

Компиляция результатов второго класса:

MyFoo.java:1: cannot find symbol
symbol: class MyFooInner
public class MyFoo extends Foo<MyFooInner> {
                               ^
1 error

Есть ли способ обойти эту проблему, помимо помещения внутреннего класса в свой собственный файл?

Ответы

Ответ 1

Используйте следующие обозначения:

public class MyFoo extends Foo<MyFoo.MyFooInner> {...

UPDATE. Статические вложенные классы фактически являются классом верхнего уровня, как указано здесь:

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

Итак, единственный способ ссылаться на статический вложенный класс - это где-то упоминать его родительский класс. В противном случае это ссылка на импортированный класс или класс внутри одного пакета.

UPDATE. Чтобы объяснить это еще раз, другим способом ссылки на класс является его импорт следующим образом:

import my.package.MyFoo.MyFooinner;

public class MyFoo extends Foo<MyFooInner> {...

Ответ 2

Чтобы основываться на @Andrey Adamovich answer, причина этого в том, что типы, идентифицированные в объявлении класса, должны иметь смысл для членов вне этого класса. Это то же самое, как если бы я записал следующее в другом файле класса:

MyFooInner mfi = new MyFooInner()

Это не скомпилировалось бы, потому что этот класс не знал бы, что MyFooInner было - я либо должен был бы квалифицировать его, написав MyFoo.MyFooInner, либо использовать import MyPackage.MyFoo.MyFooInner;. Эта же логика применяется к объявлениям классов.

По той же причине вложенные классы, объявленные private, вообще не могут использоваться в объявлении родительского класса.