我在列表中使用通配符和下界泛型,但编译器却抛出了错误。
代码:
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讨论,但无法找到为什么我应该超越错误。
答案 0 :(得分:5)
使用
List<? super Integer>
,我应该被允许添加任何Integer类型的对象或其超类型,例如数字或对象。
这是不正确的。 List<? super Integer>
并不意味着一个可以包含任何超类型Integer 的列表。它表示一个列表,其泛型类型可能是某些特定的Integer 超类型。实际上它可能是List<Object>
,List<Number>
或List<Integer>
。所有这些列表类型都可能包含Integer
,但Number
不能说明相同。 Number
可能是Double
或Long
,List<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给出了非常好的详细解释。)