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

Dev*_*taK 1 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
Run Code Online (Sandbox Code Playgroud)

错误:

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

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

shm*_*sel 5

有了List<? super Integer>,我应该被允许添加任何Integer类型的对象或其超类型,例如Number或Object.

那是不对的.List<? super Integer>并不意味着可以包含任何超类型Integer的列表.它表示一个列表,其泛型类型可能是某个特定的Integer超类型.所以它实际上可能是List<Object>,List<Number>或者List<Integer>.所有这些列表类型可能包含一个Integer,但同样不能说Number.A Number可能是a Double或a Long,在a中是不允许的List<Integer>.

为了使它更具体,请考虑以下片段:

Long longValue = 2L;
List<Integer> listOfIntegers = new ArrayList<>();
// listOfIntegers.add(longValue);
Run Code Online (Sandbox Code Playgroud)

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

Number longAsNumber = longValue;
List<? super Integer> listOfSuper = listOfIntegers;
listOfSuper.add(longAsNumber);
Run Code Online (Sandbox Code Playgroud)

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


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

void addInt(List<Integer> list) {
    list.add(1);
}
Run Code Online (Sandbox Code Playgroud)

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

这仅在列表使用相关泛型类型时才有效.如果该方法试图从列表中生成值,则会强制假定它们是类型Object,因为我们没有明确的超类型.有关更多信息,请参阅什么是PECS(生产者扩展消费者超级)?