2011-04-27 102 views
0

我有点困惑Java泛型Java泛型混乱

下面是代码

class Base{} 

class Derived extends Base{} 

我们可以实例化这样

List<? extends Base> list = new ArrayList<Base>(); 

列表为什么我不能添加迈上了一个新这样的项目

list.add(new Base()); 

所以用户不能像通配符那样使用“add”方法?在遗传学类型?

谢谢

回答

7

PECS - 生产者延伸,超级消费者。

如果用替换为super,则可以添加new Base()

List<? extends Base>的意思是“保存库(或Base本身)的任意子类的实例列表。但如果你想它不能容纳两个不同的子类的实例。

列表持有BaseDerived,然后用List<Base>,但请注意,它不能晚投地List<Derived>

+1

这个缩写本身并不是很有用;有关详细信息,请参阅[此SO问题](http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs)。 – Pops 2011-04-27 21:49:12

+0

@ Tordamus阁下 - 是的,我已经在扩大我的答案以添加正确的解释。 – Bozho 2011-04-27 21:49:55

+0

但是将类型声明为List <?当你正在给它分配一个'ArrayList '时,超级Base>'没有任何意义。通配符适用于当您不知道确切的类型参数时,因为它是从别处提供的。 – ColinD 2011-04-27 21:50:02

1

就让它

List<Base> list = new ArrayList<Base>(); 

,则不应使用WIL dcards当你知道实际的类型时......只是当你提供某种未知类型的东西时。

在这种情况下,? extends Base意味着List只允许包含某个特定的子类型Base,但您不知道是哪个子类型。因此,除了null之外,您无法添加任何内容。

1

你可以尝试阅读?的东西:

List<? extends Base> 

这是 “东西延伸BaseList”。所以,很显然,你不能添加一个Base(就像即使String延伸Object您不能添加一个ObjectList<String>

什么,你可以在你的情况做的是:

List<? super Base> 

这是“的东西是由Base”扩展List。所以,你可以添加一个Base那里(就像你可以在String添加到List<Object>,因为ObjectString延长。

0

我认为这是一个Java泛型的设计。编译通配符? extends Base意味着集合引用可以指向一个集合对象,该集合对象可以包含扩展Base的任何(和全部)类型。你可以这样写,以及:

List<? extends Base> _listBaseSubtypes = new ArrayList<Derived>(); 

现在,上述行,如果你想想看,以下将是明显的错误:

 _listBaseSubtypes.add(new Base()); 

我认为Java设计者决定允许第一行代码有效。为了避免第二行代码可能导致的运行时错误,它在编译时被捕获。

话虽如此,想到的问题是:什么类型的对象应该被允许添加到集合中,因为实际的集合对象可以是任何派生类型的集合?

因为您可以根据需要派生尽可能多的类型,并且找不到与实际集合对象中保存的类型兼容的单一类型(请记住,集合对象可以声明为保存'任何'派生类型),问题的简单答案是:无。因此,不能通过添加接口将任何对象添加到集合中,因为对于任何可能尝试传入add方法的对象,都会出现编译器异议,因为此类型与实际类型不兼容集合对象成立。