我在列表上使用通配符和下限泛型,但是编译器抛出错误。
码:
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(capture#8-of?super Integer)不适用于参数(Number)
使用List<? super Integer>,应该允许我添加任何类型Integer或其超类型的对象,例如Number或Object。我已经进行了一些SO讨论,但是找不到为什么我应该克服错误。
List<? super Integer>
Integer
使用List<? super Integer>,应该允许我添加Integer类型或其超类型的任何对象,例如Number或Object。
不对 List<? super Integer>并不意味着 可以容纳Integer的任何超类型的列表 。这意味着 其泛型可能是 Integer的某些 特定 超类型的列表。因此,它实际上可能是List<Object>,List<Number>或List<Integer>。所有这些列表类型都可以包含一个Integer,但不能说相同Number。一个Number可能是一个Double或一Long,这是不是在允许的List<Integer>。
List<Object>
List<Number>
List<Integer>
Number
Double
Long
为了更具体一点,请考虑以下代码段:
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由于我们没有确定的超类型,将被迫假定它们为类型。
Object