The problem is due to a JLS specification that mandates that otherwise uninferrable type arguments must be inferred as Object
, even if it doesn't satisfy the bounds (and would consequently trigger a compilation error).
The following is an excerpt from the "bug" report (which has been further annotated for clarity):
This program does not compile:
public class Try {
void m() {
java.util.Collections.max(null);
}
}
State: CLOSED, NOT A DEFECT.
Evaluation: THIS IS NOT A BUG. The inference algorithm cannot gather any information from the argument (null
) and the method is not called in a place where there are any expectations on the returned value. In such cases the compiler must infer java.lang.Object
for the type variable.
JLS 15.12.2.8 Inferring Unresolved Type Arguments
Any remaining type variables that have not yet been inferred are then inferred to have type Object
However, Object
is not a subtype of Comparable<? super Object>
and thus not within the bounds of the type variable in the declaration of Collections.max
:
<T extends
Object & Comparable<? super T>
> T max(Collection<? extends T>)
Further explorations
Using explicit type parameters "fixes" the problem:
HowBizarre.<Number,Integer>doIt(null); // compiles fine in javac
To show that this has less to do with a null
argument and more to do with the absolute lack of information for type inferrence, you can try e.g. either of the following declarations:
<T,U extends Comparable<T>> void doIt()
<T extends Number,U extends T> void doIt()
In either case, an invocation doIt();
doesn't compile in javac
, as it must infer U
to be Object
as per 15.12.2.8, even if doing so would trigger a compilation error.
Note on Eclipse
While none of the snippets above compile in some version of javac
, they all do in some version of Eclipse. This would suggest a bug on Eclipse's part. It's been known that there are disagreements between the different compilers.
Related questions