generics不允许将A的超类型添加到列表中
我在列表中使用通配符和下界generics,但编译器抛出错误。
码:
int intStart = 0; Number num = new Integer(2); List listOfNumbers = new ArrayList(); listOfNumbers.add(intStart); listOfNumbers.add(num); //throws compiler error
错误:
类型List中的方法add(capture#8-of?super Integer)不适用于参数(Number)
用List
List
,我应该被允许添加Integer
类型的任何对象或其超类型,例如Number或Object。 我经历了一些SO讨论,但无法找到为什么我应该犯错误。
用
List super Integer>
List super Integer>
,我应该被允许添加Integer类型的任何对象或其超类型,例如Number或Object。
那是不对的。 List super Integer>
List super Integer>
并不意味着可以包含任何超类型Integer的列表 。 它表示一个列表,其generics类型可能是某个特定的Integer超类型 。 所以它实际上可能是List
, List
或List
。 所有这些列表类型都可能包含一个Integer
,但对Number
却不一样。 Number
可能是Double
或Long
,在List
是不允许的。
为了使它更具体,请考虑以下片段:
Long longValue = 2L; List listOfIntegers = new ArrayList<>(); // listOfIntegers.add(longValue);
注释行显然不应该编译,也不应该编译。 但是,如果我们添加了这个:
Number longAsNumber = longValue; List super Integer> listOfSuper = listOfIntegers; listOfSuper.add(longAsNumber);
这相当于您问题中的代码段。 最后一行应该编译吗? 如果是的话,它将违反List
的generics不变量。
在回复您的评论时, List super Integer>
你的例子中确实没有List super Integer>
。 更常见的情况是增加方法参数的灵活性。 例如,一种方法
void addInt(List list) { list.add(1); }
只能接受List
,这将是不必要的限制。 将参数类型更改为List super Integer>
List super Integer>
允许该方法接受List
以及List
,其中任何一个都可以包含Integer
值。
这仅在列表使用相关generics类型时才有效。 如果该方法试图从列表中生成值,则会强制假定它们是Object
类型,因为我们没有明确的超类型。 有关更多信息,请参阅什么是PECS(生产者扩展消费者超级)?
List super Integer>
List super Integer>
有点奇怪。 您只能添加整数(int获取自动装箱到整数)。 您不能添加数字,因为List
不允许这样,即使List
是List super Integer>
的有效赋值List super Integer>
List super Integer>
,因为您可能正在使用List
。 由于编译器不确定,它不会允许不安全的操作。
所以简而言之,当使用List super Integer>
List super Integer>
,唯一可以安全读取的类型是Object,唯一可以安全写入的类型是Integer。 编译器不允许它,因为它是一个不安全的操作。
(有关进一步阅读, 这个答案给出了相关的generics的详细解释)