Java Generics Curiosity

У меня есть интерфейс A, какой класс B реализует.

Следующий универсальный метод работает

public static <T, U extends T> List<T> listFactory(Collection<U> source) {
    return new ArrayList<T>(source);
}

но

public static <T> List<T> listFactory(Collection<? extends T> source) {
    return new ArrayList<T>(source);
}

не (ошибка компиляции, несоответствие типов), когда я направляю вывод в

List<A> tester = listFactory(B.defaultCollectionFactory(3));

defaultCollectionFactory(int count) статически обеспечивает коллекцию Bs, со схемой маркировки по умолчанию.

Любое понимание того, почему это так? Кажется, что универсальный U и подстановочный знак делают то же самое.

2 ответа

Решение

В первой конструкции вы указываете, что возвращаете List интерфейса переданного элемента. Вы указываете связь между переданным в Object и возвращаемым типом Object в U extends T направление. В этом случае компилятор может ассоциировать A а также B с T а такжеU соответственно.

Во втором случае такой дифференциации нет, поэтому компилятор предполагает, что T относится к B и введите возвращаемое значение как List<B>, Затем вы попадаете в ловушку, где, хотя B это пример A, List<B> не является примером List<A>, Компилятор будет жаловаться:

Несоответствие типов: невозможно преобразовать из списка в список

Вы обнаружите, что с первой конструкцией вы можете указать List любого интерфейса B реализует или любой суперкласс в B иерархия (List<Object>, например), и компилятор не будет жаловаться.

Компилятор выводит другой тип параметра для listFactory метод, чем вы ожидаете. Это означает, что T это тип BТаким образом, подпись эффективно List<B> listFactory(Collection<? extends B> source), Укажите параметр типа A будучи явным в вызове метода:

List<A> tester = Test.<A> listFactory(B.defaultCollectionFactory(3));
Другие вопросы по тегам