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

u3r8eeie  于 2023-05-21  发布在  Java
关注(0)|答案(7)|浏览(517)

我有一个上限泛型列表。

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

我不明白这个问题,因为整数和双精度浮点数扩展了数字。

ewm0tg9j

ewm0tg9j1#

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));

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

vkc1a9a2

vkc1a9a22#

上界和无界通配符集合是不可变的。
例如,您不能执行以下操作:

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>Number的任何子类的List。由于不能将Double添加到List<Integer>,反之亦然,因此编译失败。

pu82cl6c

pu82cl6c3#

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

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

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

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

好消息是Java阻止我们这样做,因为这会引入很多bug。
这同样适用于未绑定的泛型类型。
那么下界泛型呢?

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,这也很好,因为一个Numbers列表可以包含一个Integer(因为Integer是一个Number)。
这可能令人惊讶,但您不能将任何不可分配给Integer的内容添加到这个列表中,原因与我上面解释的下界泛型相同。

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

由于编译器不知道将使用哪个确切类型的List,因此它不允许我们添加任何可能破坏泛型给出的承诺的内容。
希望能帮上忙。

jqjz2hbq

jqjz2hbq4#

因为List<? extends Number>意味着你的变量l持有一个List类型的值,其中具体(但未知!)扩展Number的类型参数。
您只能添加null,因为l可以容纳List<MyClass>,例如,其中MyClass是扩展Number的类,但IntegerDouble值都不能转换为MyClass

cclgggtu

cclgggtu5#

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

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

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

s2j5cfk0

s2j5cfk06#

是,以防

List<? extends Number>

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

List<Integer>

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

ecfdbz9o

ecfdbz9o7#

那么为什么我不能在上限泛型中添加元素呢?.

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

我相信**'L'是一个引用变量,可以指向ArrayList of Numbers或Number的子类(Integer,double等...)。
在某个时间点,如果'L'引用了
Integer的ArrayList,这意味着向列表中添加Double值是很奇怪的,为什么因为'L'只是指向Integer的ArrayList引用变量**,而你不能添加任何Integer以外的东西。
所以如果**'L'指向整数列表,那么我可以向它添加整数。你不能,因为这里**'L'是Number的上界,编译器不确定它是否指向整数列表,数字,double或Number的其他子类,所以它说,我不会向列表添加任何东西,即使****L指向整数数组列表,你试图添加一个像3这样的整数。
在上面的情况下,最好不要添加一个整数,因为在某个时间点,L可以指向double的列表,可怜的我试图添加除了double之外的东西......(想象一下你把List<?extends Number> L as method parameter or something and some one passes list of Integer one time,float the next day).请纠正我,如果我错了.. seri正确的varen!

相关问题