为什么不能在上限泛型列表中添加元素?

时间:2014-01-27 14:15:40

标签: java

我有一个带有上限泛型的列表。

 List<? extends Number> l = new ArrayList<>();
 l.add(new Integer(3));  //ERROR
 l.add(new Double(3.3)); // ERROR

我不明白这个问题,因为Integer和Double扩展了Number。

6 个答案:

答案 0 :(得分:20)

List<? extends Number>并不意味着“一个可以容纳Number的子类的所有对象的列表”,它意味着“一个参数化为一个扩展Number的具体类的列表”。它不是你定义的列表本身的内容,它是分配给变量的实际列表对象的参数化类型可以是什么(男孩,这比理解它更难解释:))

所以,你可以这样做:

List<? extends Number> l = new ArrayList<Integer>();
List<? extends Number> l = new ArrayList<Double>();

如果您想要一个能够容纳类Number或其子类的任何对象的列表,请执行以下操作:

List<Number> l = new ArrayList<>();

l.add(new Integer(33));
l.add(new Double(33.3d));

(插入值的装箱是不必要的,但为了清楚起见..)

答案 1 :(得分:4)

上限和无界通配符集合是不可变的。

例如,您不能这样做:

List<? extends Number> myList = new ArrayList<Integer>();
myList.add(new Integer(3)); //will not compile

这无法编译,因为java在编译时不知道List List<? extends Number>的类型。

上面的示例,在编译时,myList可以是List<Double>List<Integer>List的任何子类Number。由于您无法将Double添加到List<Integer>或反之亦然,因此编译失败。

答案 2 :(得分:3)

泛型上限的问题在于,编译器不知道将要使用的确切类型,例如:

List<? extends Number> upperBounded = new ArrayList<Integer>();
upperBounded = new ArrayList<Double>();

upperBounded可以是整数列表,也可以是双精度列表或Number的任何其他后代。现在想象一下,如果Java允许我们将Number的任何子类添加到该列表中,将会发生什么情况。

List<? extends Number> upperBounded = new ArrayList<Integer>();
upperBounded.add(1.0); // compile-time error

Java阻止我们这样做的好处是,这会引入很多错误。

无限制的泛型类型也是如此。

现在下界泛型又如何呢?

List<? super Integer> lowerBounded = new ArrayList<Integer>();
lowerBounded.add(0);

这非常好,因为我们可以安全地假定可以将Integers添加到Integer超类的任何List,并且不会导致不一致,例如:

List<? super Integer> lowerBounded = new ArrayList<Number>();
lowerBounded.add(0);

在这里,我们有一个引用,该引用允许一个整数列表或一个整数超类型。 ArrayList of Numbers符合该定义,因此我们可以将其分配给该引用。然后我们可以向该列表添加一个整数,这也很好,因为数字列表可以包含一个整数(因为整数是一个数字)。

这可能令人惊讶,但是出于与我上面针对下界泛型的解释相同的原因,您不能将无法分配给Integer的任何内容添加到此列表中。

List<? super Integer> lowerBounded = new ArrayList<Number>();
lowerBounded.add(1.0); // compile-time error

由于编译器不知道将使用哪种确切类型的列表,因此它不允许我们添加任何可能破坏泛型给出的承诺的东西。

希望有帮助。

答案 3 :(得分:1)

因为List<? extends Number>表示您的变量l包含类型List的值,其中具体(但未知!)类型参数扩展{{1} }。

您只能添加Number,因为null可以包含l,其中List<MyClass>是您的扩展MyClass的类,但也不是Number {1}},也不能将Integer值投放到Double

答案 4 :(得分:1)

我将添加一种方法将Number的子类型添加到此列表中。即

List<? super Number> l = new ArrayList<>();
 l.add(new Integer(3));  //OK
 l.add(new Double(3.3)); //OK

这是允许的,因为列表被参数化为Number类的任何未知超类型。因此,编译器允许已知的Number子类型。即IntegerDouble类型

答案 5 :(得分:0)

的情况
List<? extends Number> 

这只是一个参考,可能是实际的对象

List<Integer>

所以不应该允许在Integer列表中添加新的Double(5.0)。