2017-01-07 5 views
0

Это может быть глупый вопрос, поэтому, пожалуйста, извините мое невежество.Общие сведения о Java Generics <T extends Class> и <? extends Class>

Допустим, у меня есть класс:

public class Foo<T extends Base> implements Bar<T> { 
    private Bar<T> wrapped; 
    public void setWrapped(Bar<T> input) { 
     wrapped = input; 
    } 
} 

Если я называю его:

//Lets just assume methods getNewVal and getFoo exist 
Bar<? extends Base> val = getNewVal(); 
Foo<? extends Base> foo = getFoo(); 
foo.setWrapped(val); 

компилятор говорит foo.execute (значение) ошибка. С сообщением по линиям Метод setWrapped (Bar < захват # 20-of? Extends Base >) в виде Foo < захват # 20-из? extends Base > не применим к аргументам (Bar < capture # 22-of? extends Base >).

Если я пытаюсь изменить Foo быть

public class Foo<T extends Base> implements Bar<T> { 
    private Bar<T> wrapped; 
    public void setWrapped(Bar<? extends Base> input) { 
     wrapped = input; 
    } 
} 

Вызов foo.setWrapped (VAL) больше не ошибок. Вместо этого wrapped = input является ошибкой с сообщением в строке Тип несоответствия: не удается преобразовать из Bar < capture # 1-of? extends Base > to Bar <T>.

Что я делаю неправильно? Нет ли способа заставить компилятор быть в порядке с таким вызовом без кастинга?

+4

Это потому, что '?' Не совпадает с '?'. Компилятор не может проверить, что '?' В 'Bar 'является * тем же *'? 'как в' Foo ', поэтому они несовместимы. – Andreas

+0

Практически нет способа использовать подстановочный знак в качестве возвращаемого типа, что вы делаете во втором примере кода. C.F. PECS http://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super Эти подстановочные знаки предназначены для упрощения использования дженериков с параметрами метода, а не с возвращаемыми типами. – markspace

+1

Пример: 'getNewVal()' возвращает 'Bar ', и 'getFoo()' возвращает 'Foo '. Это совершенно верно для первых двух операторов, но не для 'setWrapped()'. – Andreas

ответ

0

Похоже, что вы хотите является

public class Foo { 
    private Bar<? extends Base> wrapped; 
    public void setWrapped(Bar<? extends Base> input) { 
     wrapped = input; 
    } 
} 

Это не ясно, что интерфейс BarFoo должен реализовать это, хотя, и почему Foo должны иметь Bar, а также бытьBar ,

Смежные вопросы