2014-03-04 73 views
0

假设我们有2个不同的列表。列表泛型协变

列表1可以接受任何Number参数(包括int,double,float和Number的子类的其他所有内容)。

List<Number> l1 = new ArrayList(); 

因此,这样做的作品非常好。

l1.add(123); 
    l1.add(123.3456); 

List 2 extends Number。问题是我不能添加任何东西,我不明白为什么。另外,为什么我会需要一个列表<?扩展Something>而不是仅仅创建一个层次最高的类的列表,可以存储任何子类(如列表1)?

List<? extends Number> l2 = new ArrayList(); 
    l2.add(123); //Error, although Integer is a subclass of Number 
    l2.add(new Integer(123)); // Wrappers don't work either 
    l2.add(123.456); //Error again 
+0

查找术语PECS(生产者延伸,超级消费者)。 Java方差“声明”是在使用时完成的,而不是类定义时间 –

回答

5

与主叫如add具有与一个? extends通配符一类的通用参数的方法的问题是,确切的类型是未知的给编译器。它可以是List<Number>List<Integer>List<Double>List<BigInteger>。编译器必须保留泛型的类型安全性,如果它允许这样的调用,类型安全性将不会被保留。您不应该被允许将Double添加到可能是List<Integer>的列表中。

这样的? extends上限绑定通配符本身是有用的方法参数,其中确切的类型无关紧要;它只是很重要的,这是约束(在这种情况下,Number)或更低。

public void foo(List<? extends Number> list) { 
    for (Number n : list) { 
     // do something with some kind of Number, don't care which 
+0

它给出了一个编译错误,默认为novariance。任何想法? – MMK

1

通配符不用于修改列表,仅用于处理已包含在列表中的元素。如果您创建列表或向列表添加元素,则必须知道列表中包含哪些元素。

2

?是编译器未知的通配符。它可以是从数字派生的任何类型的实例。泛型是为了类型安全的确切目的而实现的,并且由于类型进入是未知的,所以这是行不通的。