With List<? super Integer>
, I should have been allowed to add any objects of type Integer or its superTypes e.g. Number or Object.
That's incorrect. List<? super Integer>
doesn't mean a list that can hold any supertype of Integer. It means a list whose generic type may be some specific supertype of Integer. So it might actually be List<Object>
, List<Number>
or List<Integer>
. All of those list types may contain an Integer
, but the same can't be said for Number
. A Number
might be a Double
or a Long
, which isn't allowed in a List<Integer>
.
To make it a little more concrete, consider this snippet:
Long longValue = 2L;
List<Integer> listOfIntegers = new ArrayList<>();
// listOfIntegers.add(longValue);
The commented line obviously shouldn't compile, and doesn't. But what if we added this:
Number longAsNumber = longValue;
List<? super Integer> listOfSuper = listOfIntegers;
listOfSuper.add(longAsNumber);
This is equivalent to the snippet in your question. Should the final line compile? If it would, it would violate the generic invariant of List<Integer>
.
In response to your comment, List<? super Integer>
is indeed unnecessary in your example. A more common case would be to add flexibility to a method parameter. For example, a method
void addInt(List<Integer> list) {
list.add(1);
}
would only be able to accept List<Integer>
, which would be unnecessarily restrictive. Changing the parameter type to List<? super Integer>
would allow the method to accept List<Integer>
as well as List<Number>
, either of which can contain an Integer
value.
This only works if the list is consuming the generic type in question. If the method tried to produce values from the list, it would be forced to assume they're of type Object
, since we don't have a definite supertype. For more information, see What is PECS (Producer Extends Consumer Super)?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…