名单<! - ?扩展对象 - >我可以存储到什么?

时间:2014-12-23 01:29:57

标签: java generics

我是java的新手,我有这样的代码:

List<? extends Object> k = new ArrayList<Integer>();
k.add(new Integer(1));

我收到的错误如下:

Error:(13, 10) java: no suitable method found for add(java.lang.Integer)
    method java.util.Collection.add(capture#1 of ? extends java.lang.Object) is not applicable
      (argument mismatch; java.lang.Integer cannot be converted to capture#1 of ? extends java.lang.Object)
    method java.util.List.add(capture#1 of ? extends java.lang.Object) is not applicable
      (argument mismatch; java.lang.Integer cannot be converted to capture#1 of ? extends java.lang.Object)

我几乎没有问题:

  1. List<? extends Object> k = new ArrayList<Integer>();为什么在等式的右边不允许我放new ArrayList<? extends Object>()

  2. <? extends Object>表示任何类扩展Object对吗?所以在java中,所有类都扩展Object,所以我为什么会遇到错误:

  3. k.add(new Integer(1));

    1. 在声明时,java允许我提供new ArrayList<Integer>(),但允许我添加Integer为什么?
    2. 提前致谢。

2 个答案:

答案 0 :(得分:4)

  

尽管在声明时,java允许我提供新的ArrayList<Integer>

是。但是,它还允许您分配ArrayList<String>

由于您不知道列表应存储的内容,因此无法添加任何内容(null除外)。

答案 1 :(得分:0)

是的,欢迎使用java破解的通用系统。问号作为类型参数意味着“未知类型”。声明List<T>.add接受T类型的参数。所以,在你的情况下,它应该是未知的。因为Integer的类型是已知的,所以你不能这样称呼它。

为什么要使用问号作为类型参数呢?好吧,有时候,列表元素的具体类型并不重要,你只关心类型边界。 例如:

public void printDoubles(List<? extends Number> l) {
   for(Number n : l) System.out.println(n.doubleValue() * 2);
}

这可以仅用List<Number>来完成吗?好吧,事实证明,它不能,因为java中的列表(和一般的容器)在它们的元素类型上不是协变的(实际上有一个原因)。这意味着List<Integer>不是List<Number>的子类,因此,如果声明上面的函数接受List<Number>类型的参数,那么它将是相当无用的,因为你无法通过没有强制转换的整数(或任何其他数字类型)列表。

所以,为了解决这个问题,他们发明了问号。该声明实际上等同于<T extends Number> public void printDoubles(List<T> l),除了它使读者更清楚,该函数特别关注列表元素的特定具体类型。