Java Generics Curiosity - PullRequest
       34

Java Generics Curiosity

5 голосов
/ 03 октября 2009

У меня есть интерфейс 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) статически предоставляет набор B с, со схемой маркировки по умолчанию.

Есть идеи, почему это так? Похоже, универсальный U и подстановочный знак делают то же самое.

Ответы [ 2 ]

3 голосов
/ 03 октября 2009

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

List<A> tester = Test.<A> listFactory(B.defaultCollectionFactory(3));
2 голосов
/ 03 октября 2009

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

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

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

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

...