I know that Lists in Java are Invariant.
So the second statement below gives a compilation error as expected
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Number> numbers = integers;
However, all of these work fine
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<? extends Number> numbers2 = Arrays.asList(1, 2, 3);
List<Number> numbers3 = Arrays.asList(1, 2, 3);
So my question is how does the last statement above compile?
I understand that Arrays.asList()
accepts the type from its caller, but I thought Arrays.asList(1,2,3)
whould resolve to the closest type List<Integer>
and setting it to List<Number>
would not compile, since Lists are Invariant.
What am I missing?
There is no covariance going on here. Instead, Java compiler uses the context of the call to Arrays.asList<T>
to infer the type T
that your program wanted to specify for the method call.
Prior to Java 8 you could specify the type explicitly, for example
List<Integer> numbers1 = Arrays.<Integer>asList(1, 2, 3);
List<? extends Number> numbers2 = Arrays.<? extends Number>asList(1, 2, 3);
List<Number> numbers3 = Arrays.<Number>asList(1, 2, 3);
Noting how the above code snippets repeat the type T
on both sides of the assignment, Java compiler set up inference rules to propagate T
from the left side of the assignment to the right side, eliminating the repetition.
Reference: Type Inference Tutorial.