Lets suppose we have the following code:
class A {}
class B extends A {}
class C extends B {}
public static <T> T testMe(List<? super T> list1,List<? extends T> list2) {
return null;
}
public static void main(String[] args) {
List<B> listB = new ArrayList<>();
List<C> listC = new ArrayList<>();
// All three variants are possible:
A a=testMe(listB, listC);
B b=testMe(listB, listC);
C c=testMe(listB, listC);
}
The question is about public static <T> T testMe(List<? super T> list1,List<? extends T> list2)
. How does the compiler determine the T
type if if have three classes:A,B,C,
? This question arose when I analysed Collections.copy
.
To declare an upper bound on a type parameter, use the keyword extends, followed by the class or interface that is to be the upper bound.
Type inference is the ability to automatically deduce, either partially or fully, the type of an expression at compile time. The compiler is often able to infer the type of a variable or the type signature of a function, without explicit type annotations having been given.
In TypeScript, there are several places where type inference is used to provide type information when there is no explicit type annotation. For example, in this code. let x = 3; let x: number. The type of the x variable is inferred to be number .
A type parameter can have multiple bounds.
The compiler is inferring the type C
for the type parameter T
in all 3 cases.
It is the most specific type that fits the constraints.
[T]he inference algorithm tries to find the most specific type that works with all of the arguments.
For the first 2 statements,
A a = testMe(listB, listC);
B b = testMe(listB, listC);
Both B
and C
match, because a List<B>
matches List<? super B>
and List<C>
matches List<? extends B>
, and a List<B>
matches List<? super C>
and List<C>
matches List<? extends C>
. The compiler chooses the most specific type that matches, C
.
You could get this to compile with an explicit type parameter, to get the compiler to resolve it to B
:
A a = Super.<B>testMe(listB, listC);
B b = Super.<B>testMe(listB, listC);
In the third line, only C
matches, so that is what the compiler chooses for T
.
C c = testMe(listB, listC);
This happens because the variable being assigned is of type C
, and a B
can't be assigned to C
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With