2015-12-03 1 views
3

Рассмотрим следующий пример,PECS не работает на типы возвращаемых с интерфейсом

class ClsA {} 
class ClsB {} 

interface IntA {} 
interface IntB {} 

И у меня есть 2 очень похожие методы:

static <T extends ClsA> T returnC() { // Here T extends the class 
    return null; 
} 

static <T extends IntA> T returnI() { // Here T extends the interface 
    return null; 
} 

И тогда метод вызывает:

ClsA ac = returnC(); // This works fine based on inference. 

IntA ai = returnI(); // Similarly this works fine based on inference. 

Но рассмотрите ниже 2:

ClsB bc = returnC(); // ERROR as expected. 

Затмение Ошибка:

Bound mismatch: The generic method returnC() of type Testing is not applicable for the arguments(). The inferred type ClsB&ClsA is not a valid substitute for the bounded parameter <T extends ClsA>

Но следующий код компилируется нормально:

IntB bi = returnI(); // Works fine 

Почему что для интерфейса, дженерики, связанные не рассматривается типов возврата?

+0

Подтверждено с помощью javac. И JDK7u40, и JDK8u20. –

+0

PECS не имеет никакого отношения к вопросу, на самом деле :) –

ответ

1

Магические слова здесь Raws и множественного наследования.

Давайте сначала посмотрим на ваш returnC метод:

static <T extends ClsA> T returnC() { 
    return null; 
} 

Тип T ограничена с ClsA, что означает, что если вы вызываете необработанныйreturnC метод , то возвращаемый тип будет просто ClsA ,

Правда, когда у вас есть это заявление: ClsA ac = returnC(); компилятор преуспевает с компиляцией, так как сырьем типа возвращения метода ClsA, который совместит с типом ac.

Обратный тип возврата также является причиной, по которой заявление ClsB bc = returnC(); не компилируется.


Теперь давайте взглянем на метод returnI:

static <T extends IntA> T returnI() { // Here T extends the interface 
    return null; 
} 

Здесь параметр типа связан только IntA.

Это, однако, не означает, что тип для замены T должен реализовать только IntA - тип может реализовать IntA и IntB одновременно. Допускаются такие утверждения, как IntB bi = returnI();, потому что тип может реализовывать несколько интерфейсов, но не может реализовать несколько классов.

Рассмотрим этот класс:

class SomethingReallyCool implements IntA, IntB { } 

Этот тип является действительным заменой типа-параметра returnI() и доказательство, что это утверждение:

IntB bi = YourClass.<SomethingReallyCool>returnI(); 

Почему? Потому что это класс, который реализует IntA, и это единственное, о чем компилятор заботится.

+0

Делает смысл ... Я не думал о множественном наследовании вообще ... :) Спасибо ... – Codebender

+0

Добро пожаловать. –