泛型<! - ? super A - >不允许将A的超类型添加到列表中

时间:2017-05-16 17:52:29

标签: java generics arraylist

我在列表中使用通配符和下界泛型,但编译器却抛出了错误。

代码:

int intStart = 0;       
Number num = new Integer(2);                
List<? super Integer> listOfNumbers = new ArrayList<>();
listOfNumbers.add(intStart);
listOfNumbers.add(num); //throws compiler error

错误:

  

类型List中的方法add(捕获#8-of?super Integer)不适用于参数(Number)

使用List<? super Integer>,我应该被允许添加Integer类型的任何对象或其超类型,例如数字或对象。 我已经经历了一些SO讨论,但无法找到为什么我应该超越错误。

2 个答案:

答案 0 :(得分:5)

  

使用List<? super Integer>,我应该被允许添加任何Integer类型的对象或其超类型,例如数字或对象。

这是不正确的。 List<? super Integer>并不意味着一个可以包含任何超类型Integer 的列表。它表示一个列表,其泛型类型可能是某些特定的Integer 超类型。实际上它可能是List<Object>List<Number>List<Integer>。所有这些列表类型都可能包含Integer,但Number不能说明相同。 Number可能是DoubleLongList<Integer>中不允许这样做。

为了使其更具体一点,请考虑以下代码段:

Long longValue = 2L;
List<Integer> listOfIntegers = new ArrayList<>();
// listOfIntegers.add(longValue);

注释行显然不应该编译,也不应该编译。但是,如果我们添加了这个:

Number longAsNumber = longValue;
List<? super Integer> listOfSuper = listOfIntegers;
listOfSuper.add(longAsNumber);

这相当于您问题中的代码段。最后一行应该编译吗?如果愿意,它将违反List<Integer>的通用不变量。

在回复您的评论时,您的示例中确实没有List<? super Integer>。更常见的情况是为方法参数增加灵活性。例如,方法

void addInt(List<Integer> list) {
    list.add(1);
}

只能接受List<Integer>,这将是不必要的限制。将参数类型更改为List<? super Integer>将允许该方法接受List<Integer>以及List<Number>,其中任何一个都可以包含Integer值。

仅当列表消费有问题的通用类型时才有效。如果该方法试图从列表中生成值,则会强制假定它们是Object类型,因为我们没有明确的超类型。有关详细信息,请参阅What is PECS (Producer Extends Consumer Super)?

答案 1 :(得分:0)

List<? super Integer>有点奇怪。您只能添加整数(int获取自动装箱到整数)。您无法添加号码,因为List<Integer>中不允许这样做,即使List<Number>List<? super Integer>的有效分配,因为您可能正在使用{{1} }}。由于编译器不确定,它不会允许不安全的操作。

简而言之,当使用List<Integer>时,唯一可以安全读取的类型是Object,唯一可以安全写入的类型是Integer。编译器不允许它,因为它是一种不安全的操作。

(如需进一步阅读,this answer给出了非常好的详细解释。)