简体   繁体   English

java中的通用集合和通配符

[英]Generic collection & wildcard in java

I am having problems getting my head around generics in the following situation, see inline comments below for my questions: 在以下情况下我遇到问题,请参阅下面的内联评论:

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?  
}
//Intuitively I would expect this to mean that test is set containing objects 
//that subclass AbstractGroup
Set<? extends AbstractGroup> test;

Nope, it means that it's a set of one specific ? 不,这意味着它是一组特定的? which extends AbstractGroup. 它扩展了AbstractGroup。 And neither you nor the Compiler have any way of knowing what that ? 你和编制者都没有办法知道那是什么? is, so there's no way you can add anything to that Set. 是的,所以你无法向该套装添加任何东西。

You can assign the set's values to variables of type AbstractGroup, but not the other way around. 您可以将集合的值分配给AbstractGroup类型的变量,但不能相反。

Instead, you need this: 相反,你需要这个:

Set<? super AbstractGroup> test;

This principle is sometimes called PECS and explained well in this answer . 这个原则有时被称为PECS ,并在这个答案中得到了很好的解释。

Set<? extends AbstractGroup> test;

This means your set can be a set of any object that extends AbstractGroup , but normally the compiler would not allow you to add something to that set (since it can't tell whether you'd for example add a SubGroupB to a Set<SubGroupA> etc.). 这意味着您的集合可以是扩展AbstractGroup的任何对象的集合,但通常编译器不允许您向该集合添加内容(因为它无法判断您是否SubGroupB添加到Set<SubGroupA>等)。

test = new HashSet<SubGroupA>()

Your actual set would only contain objects of type SubGroupA and subclasses thereof. 您的实际集只包含SubGroupA类型的SubGroupA及其子类。 However, the compiler would still not know what the content of test would be (see above). 但是,编译器仍然不知道test的内容是什么(见上文)。

The point of the wild card is: you can assign any set to the variable that is parameterized with AbstractGroup or a subclass, thus assuring you can cast all objects already in that map to AbstractGroup (which the compiler checks for). 通配符的要点是:您可以将任何集合分配给使用AbstractGroup或子类参数化的变量,从而确保您可以将该映射中已有的所有对象强制转换AbstractGroup (编译器检查)。

If you want to have a set that can contain any AbstractGroup object, just don't use the wildcard. 如果您想拥有一个可以包含任何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());

You don't need wildcards here In your case it would suffice to say 你不需要这里的通配符在你的情况下,它就足够了

Set<AbstractGroup> test;

And you can then put any subclass of AbstractGroup into the set. 然后,您可以将AbstractGroup的任何子类放入集合中。

Also, it doesn't look like you're initializing test in your code above. 此外,它看起来不像您在上面的代码中初始化测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM