Consider the following snippet:
List<Double> doubleList = null;
List<Integer> integerList = null;
List<Number> numberList = null;
//expression:1
List<? super List<? super Integer>> superDoubleList = Arrays.asList(doubleList, integerList,numberList);
//expression:2
//here doubleList will cause compilation error
List<? extends List<? super Integer>> extendsDoubleList = Arrays.asList(integerList,numberList);//doubleList
? super List<? super Integer>
doubleList
/ integerList
/ numberList
are not satisfying this condition anyhow - as we expect a type that is a supertype of List<? super Integer>
.subtype of List<? super Integer>
doubleList
intuitively can be seen as a candidate that can satisfy the condition.doubleList
in the Arrays.asList
expression?.Not sure if I am interpreting the expressions in the right way - and what is wrong possibly that logically it does not seem to fit the explanation I gave above?
The two cases that compiles, compiles because the type inference algorithm tries its best to infer the type parameter for the asList
call to make your code compile. It's not about the types of the three lists (they're only indirectly related). It's all about the type that Arrays.asList
returns.
In the first case:
List<? super List<? super Integer>> superDoubleList = Arrays.asList(doubleList, integerList,numberList);
To make your code compile, Arrays.asList
, just has to create a List<List<?>>
. After all, the three lists are all "lists of something", so that is possible.
And List<List<?>>
is a kind of List<? super List<? super Integer>>
. This is because List<?>
is a super type of List<? super Integer>
- "a list of some Integer
supertype" is a kind of "a list of some objects".
Another interpretation of this, is to think of ? super T
as "consumer of T
" and ? extends T
as "producer of T
". (PECS) In this interpretation, List<? super List<? super Integer>>
means "a list that can consume lists that can consume integers". "Consume" in the context of lists just means "add". Can a list containing doubleList
, integerList
and numberList
do that? Sure, it doesn't matter what the contents of the list are, you can always add another List<? super Integer>
to the list. It's just that the type of the list has to be List<List<?>>
. Even this works:
List<? super List<? super Integer>> superDoubleList =
Arrays.asList(new ArrayList<String>(), new ArrayList<LocalDate>());
Using the same interpretation, List<? extends List<? super Integer>>
means "a list that can produce lists that consume integers". Can
Arrays.asList(integerList,numberList)
do that? Yes, both of those inner lists can consume integers, so the outer list can "produce lists that consume integers", or in other words, a producer of such lists.
What about this list of lists?
Arrays.asList(doubleList,integerList,numberList)
Is it a producer of lists that can consume integers? Well, no, because doubleList
does not consume integers, but it can produce that.
You might be wondering what is the type that the Java compiler has inferred for asList
in this case:
List<? extends List<? super Integer>> extendsDoubleList = Arrays.asList(integerList,numberList);
asList
could create a List<List<? super Integer>>
. However, the actual inferred type seems to be something else, that can't be expressed in Java's syntax.