2012-09-26 22 views
3

有人可以解释我们为什么使用?在收集泛型。使用'?延伸'和'?超级'收集仿制药

如实施例:

 List<? extends Number> numberlist; 
    List<? super Integer> numberlist; 
+3

你更喜欢另一个角色? –

+0

你在问我们为什么使用这个特定的字符而不是另一个? –

+0

我已经问过类似的东西在不久前,看到... http://stackoverflow.com/questions/6826916/useful-example-with-super-and-obscurity-with-extends-in-generics [ 1]:http:// stackoverflow。com/questions/6826916 /有用的例子与超级和obscurity与扩展在泛型 – Bevor

回答

20

通配符在如何使用集合中引入限制。

例如,使用List<? extends Number>,我无法将新元素添加到列表中。这是因为我所知道的是该列表是Number的某种子类型,但我不知道该实际的子类型是什么(所以我怎么知道要添加什么?)。例如,采取以下代码:

public void doSomethingWith(List<? extends Number> numbers) { 
    numbers.add(Integer.valueOf(0)); // Won't compile 
} 

这不能编译,因为两者的这些方法调用是合法的:

doSomethingWith(new ArrayList<Integer>()); 
doSomethingWith(new ArrayList<Double>()); 

什么你可以做的是读取元素清单:

// This will all compile 
public void doSomethingWith(List<? extends Number> numbers) { 
    for (Number number : numbers) { 
     // Do something with number 
    } 
    // OR 
    Number number = numbers.get(0); 
    // OR 
    Number number = numbers.remove(0); 
} 

调用方法如get会返回某种Number,我们知道由于? extends Number这个事实,所以我们可以把它看作是为了阅读目的。

另一方面,List<? super Integer>有完全相反的结果。我不能再从列表中读取,但我可以写信给它。我知道无论?是什么,它肯定会是Integer的超级类别,所以列表的具体类型肯定会接受Integer的值。例如:

public void doSomethingWith(List<? super Integer> integers) { 
    integers.add(Integer.valueOf(0)); 
} 

该代码是完全合法的。但是,如果你想从列表中读取,要做到这一点的唯一方法是使用Object因为别的需要铸造(这需要知道它的具体类型):

for (Object obj : integers) 
// OR 
Object obj = integers.get(0); 
// OR 
Object obj = integers.remove(0); 

真正的情况

以下是实际发生的情况。当您指定? extends Number时,您正在使任何方法元素作为参数不可用。实际上,如果您尝试在List<? extends Number>上使用Ctrl + Space自动完成Eclipse中的代码,则会在add方法等中显示null作为参数的类型。同时,返回元素的所有方法都保证返回至少某种类型的Number,尽管您不知道它实际上可能是哪个子类的Number

当你指定? super Integer,你正在做的是需要元素作为参数,保证他们会接受Integer值(和子类Integer以及)的任何方法。这允许你调用像add这样的方法,因为你知道他们会接受Integer类型。同时,返回元素的所有方法只保证返回东西,但我们不知道是什么,所以返回元素的所有方法只保证返回Object

PECS是一个极好的缩写记住这一点,它的意思是 “P roducer ë xtends,Ç onsumer 小号 upers”。这意味着如果你想让你的名单给你一些东西,这是一个制片人,你应该使用extends。如果你想让你的名单接受你的东西,这是一个消费者,所以你使用super。有关更多信息,请参阅this answer

但是如果我有一个没有界限的通配符?

它既! <?>限制您从调用使用泛型类型作为参数的方法导致所有返回泛型类型的方法返回Object。这是因为我们不知道这种类型是什么。例如,所有这些分配到一个List<?>是合法的:

List<?> list; 
list = new ArrayList<Integer>(); 
list = new ArrayList<String>(); 
list = new ArrayList<MyClass>(); 

等。

+2

优秀的答案!谢谢! – bsiamionau

1

?使用,而使用泛型定义wild cards

你例子有声明告诉列表接受类型的任何对象Number

1

?意味着任何类,所以

? extends MyClass 

意味着MyClass的MyClass的还是自身的任何子类。

2

它是一个通配符。 ?表示从数字继承的任何类或Integer类的超类都可以工作。希望这可以帮助。 :)

0

这是我要说的话:

List<? extends Number> numberlist; //Any class that is extended from Number class, for example Integer, BigInt, ... may come 

List<? super Integer> numberlist; //Any class that Integer class is extended from. Here for example Number may come 

因为:

Integer extends Number{ 
} 
2

当你正在学习通配符和DIFF之间延伸超级,只需记住PECS。这条规则的所有内容都非常简单易记。

0

List<? extends Number>List<Number>既能允许添加例如整数,但: 随着List<Number>你可以把在那里的整数和其他任何“是”一个号码。使用List<? extends Number>,您可以只在其中放入一个具体的运行时类型。是整数,那么你不能添加另一个也是数字的类型。