Нарушение видимого типа, но компилирует

Почему выполняется компиляция следующего фрагмента? OtherInterface не расширяет Concrete, поэтому я бы поставил почку, что это не скомпилируется. Но это так.

public class Test {

    public static interface SomeInterface {}

    public static interface OtherInterface{}

    public static class Concrete implements SomeInterface {

       public <T extends Concrete> T getConcrete() {
            return null;
       }
    }

    public static void doStuff() {
        Concrete c = new Concrete();
        OtherInterface iCompile = c.getConcrete();
    }
}

С другой стороны, следующий фрагмент не компилируется, что я и ожидаю.

public class Test {

    public static interface SomeInterface {}

    public static class UnrelatedClass{}

    public static class Concrete implements SomeInterface {

       public <T extends Concrete> T getConcrete() {
            return null;
       }
    }

    public static void doStuff() {
        Concrete c = new Concrete();
        UnrelatedClass iCompile = c.getConcrete();
    }
}

Ответ 1

Разница здесь:

public static interface OtherInterface{} ...
OtherInterface iCompile = c.getConcrete();

против.

public static class UnrelatedClass{} ...
UnrelatedClass iCompile = c.getConcrete();

Значение: в первом случае вы вызываете метод для возврата экземпляра некоторого интерфейса. Интерфейсы могут быть любыми классами.

Во втором примере вы указываете, что возвращаемый тип является определенным классом! Класс, который известен, и что не выполняет другой интерфейс!

И сообщение об ошибке:

причина: не существует уникального максимального экземпляра для переменной типа T с верхними границами UnrelatedClass, Concrete

довольно специфичен здесь.

Другими словами: факторы компилятора в левой части этого присваивания - для определения допустимых типов. И UnrelatedClass никогда не может быть Concrete - потому что класс UnrelatedClass не поддерживает не Concrete!

В то время как то, что есть SomeInterface, может также реализовать OtherInterface.