Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is type inferred where return type is also upper and lower bound for method parameters

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.

like image 215
Pavel_K Avatar asked Sep 01 '15 16:09

Pavel_K


People also ask

What keyword can we use to set a upper type bound on a type parameter for a class?

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.

What is meant by type inference?

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.

What is type inference in TypeScript?

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 .

Can a parameterized type have several bounds?

A type parameter can have multiple bounds.


1 Answers

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.

like image 74
rgettman Avatar answered Sep 29 '22 23:09

rgettman