Общая коллекция и подстановочный знак в Java - PullRequest
3 голосов
/ 09 сентября 2011

У меня проблемы с поиском дженериков в следующей ситуации, см. Встроенные комментарии ниже для моих вопросов:

public void exampleMethod() {
    //Intuitively I would expect this to mean that test is set containing objects 
    //that subclass AbstractGroup
    Set<? extends AbstractGroup> test;

    //Yet the compiler complains here and I do not understand why?

    test.add(new AnyAbstractGroupSubGroup());

    //I would guess that a method call such as this at runtime

    test = new HashSet<SubGroupA>()

    //would mean that only objects of subgroupA can be added to the collection, but then
    //what is the point in using the wildcard in the first place?  
}

Ответы [ 3 ]

8 голосов
/ 09 сентября 2011
//Intuitively I would expect this to mean that test is set containing objects 
//that subclass AbstractGroup
Set<? extends AbstractGroup> test;

Нет, это означает, что это набор одного конкретного?который расширяет AbstractGroup.И ни у вас, ни у Компилятора нет никакого способа узнать, что это?есть, поэтому вы никак не можете добавить что-либо к этому набору.

Вы можете присвоить значения набора переменным типа AbstractGroup, но не наоборот.

Вместо этого вам нужно это:

Set<? super AbstractGroup> test;

Этот принцип иногда называют PECS и хорошо объясняется в этом ответе .

4 голосов
/ 09 сентября 2011

Set<? extends AbstractGroup> test;

Это означает, что ваш набор может быть набором любого объекта, который расширяет AbstractGroup, но обычно компилятор не позволяет вам добавить что-либо к этому набору (так как он не может сказать, например, хотите ли вы добавить * От 1007 * до Set<SubGroupA> и т. Д.).

test = new HashSet<SubGroupA>()

Ваш фактический набор будет содержать только объекты типа SubGroupA и их подклассы. Однако компилятор все равно не знает, каким будет содержимое test (см. Выше).

Точка подстановочного знака такова: вы можете назначить любой набор переменной, параметризованной с помощью AbstractGroup или подкласса, таким образом гарантируя, что вы можете привести все объекты , уже находящиеся в , которые сопоставляются с AbstractGroup (который проверяет компилятор).

Если вы хотите иметь набор, который может содержать любой объект AbstractGroup, просто не используйте подстановочный знак.

//this would compile (under the assumption that SubGroupA extends AbstractGroup)
Set<? extends AbstractGroup> test = new HashSet<SubGroupA>(); 

//this wouldn't compile, since the compiler doesn't know the type of test (it might change at runtime etc.)
test.add(new SubGroupA());


//this wouldn't compile since AbstractGroup and SubGroupA are not the exact same type (hence the wildcard would be needed here)
Set<AbstractGroup> test = new HashSet<SubGroupA>();

//this would compile
Set<AbstractGroup> test = new HashSet<AbstractGroup>();
test.add(new SubGroupA());
2 голосов
/ 09 сентября 2011

Здесь вам не нужны символы подстановки. В вашем случае достаточно было бы сказать

Set<AbstractGroup> test;

И затем вы можете поместить любой подкласс AbstractGroup в набор.

Кроме того, не похоже, что вы инициализируете тест в приведенном выше коде.

...