我有一个带有上限泛型的列表。
List<? extends Number> l = new ArrayList<>();
l.add(new Integer(3)); //ERROR
l.add(new Double(3.3)); // ERROR
我不明白这个问题,因为Integer和Double扩展了Number。
答案 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
子类型。即Integer
和Double
类型
答案 5 :(得分:0)
是
的情况List<? extends Number>
这只是一个参考,可能是实际的对象
List<Integer>
所以不应该允许在Integer列表中添加新的Double(5.0)。