为什么我们不能使用extends bounds在java泛型中添加元素?

时间:2017-08-10 09:27:40

标签: java generics

我知道我们无法在列表中添加元素,这是扩展边界的类型。但我仍然不确定为什么java编译器不允许这样做。因为编译器可以很容易地检查添加新元素是否是Generic类型的子类型。有人可以帮我这个吗?

2 个答案:

答案 0 :(得分:1)

此案例称为协方差,extends关键字允许您从Collection读取元素,但不能添加它们。这是因为编译器将add操作视为不安全。例如,您可以声明以下任何列表:

List<? extends Number> myNums = newArrayList<Integer>(); 
List<? extends Number> myNums = newArrayList<Float>(); 
List<? extends Number> myNums = newArrayList<Double>();

您可以毫无问题地从中读取,因为无论列表包含什么,都可以上传到Number。但是,您不能将任何内容放入任何内容中:

myNums.add(45L); //compiler error

这是由于编译器无法确定通用列表的实际类型(可能是IntegerFloatDouble在我们的示例中) 。因此,这是一个不安全的操作,您可能会在Long列表中添加Integer,因此编译器不允许您这样做。

阅读this文章以获得更深入的解释。

答案 1 :(得分:0)

我将使用here中的示例修改:

List<String> ls = new ArrayList<String>();
List<? extends Object> l = ls;
l.add(l, new Object()); // not legal - but assume it was!
String s = ls.get(0); // ClassCastException - ls contains
                      // Objects, not Strings.

您非常正确地指出“编译器可以轻松检查添加新元素是否是Generic类型的子类型”。但即便如此,由于编译器无法确定列表l的类型,因此接受l.add(l, new Object())会导致列表ls损坏。

因此编译器正在完成它的工作,它比运行时检查更早地捕获错误。