In the Collections.java
class is present the following method:
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
I was wondering how the type T is defined! Usually the type parameter is used in the method parameter, and I can imagine that at Compile time, T is replaced, based on the parameter used. Example:
public static final <T> List<T> returnList(List<T> list) {
return list;
}
...
List<String> list = ...;
Collections.returnList(list); // I know that it returns a List of string, since list is defined to contain String elements.
but how T is inferred here:
Collections.emptyList(); // It returns a list, but how T is inferred?
CodePudding user response:
See Chapter 18 of the JLS for the exact process of type inference. Notably in this case, practically no expressions participate in type inference, and only the type parameters of the methods do. So the most relevant part that you need to look at is the end of §18.1.3:
When inference begins, a bound set is typically generated from a list of type parameter declarations P1, ..., Pp and associated inference variables α1, ..., αp. Such a bound set is generated as follows. For each l (1 ≤ l ≤ p):
If Pl has no TypeBound, the bound αl <: Object appears in the set.
Otherwise, for each type T delimited by & in the TypeBound, the bound αl <: T[P1:=α1, ..., Pp:=αp] appears in the set; if this results in no proper upper bounds for αl (only dependencies), then the bound αl <: Object also appears in the set.
For Collections.emptyList
, the type parameter T
has no bound, so the first case applies. Now T
has an upper bound of Object
. Then this is resolved, and another bound that says T = Object
is incorporated, according to §18.4 Resolution, and so, T
is inferred to be Object
.
In general, (oversimplifying the JLS) for a statement of the form f();
where f
is generic method with type parameter T
, all the bounds of T
(let's call them B1...Bn) gets added (as proper upper bounds) to a bound set. That bound set is resolved to the greatest lower bound (glb) of B1...Bn, and that is the inferred type.
But alas, this doesn't really matter practically though. The type parameters are all erased at runtime. So although the spec says all of the above, in reality the compiler could very well be implemented to not do any type inference at all when it sees:
Collections.emptyList();