The following code compiles perfectly with Eclipse, but fails to compile with javac:
public class HowBizarre {
public static <P extends Number, T extends P> void doIt(P value) {
}
public static void main(String[] args) {
doIt(null);
}
}
I simplified the code, so T is not used at all now. Still, I don’t see a reason for the error.
For some reason javac decides that T stands for Object, and then complains that Object does not conform to the bounds of T (which is true):
HowBizarre.java:6: incompatible types; inferred type argument(s)
java.lang.Number,java.lang.Object do not conform to bounds of type
variable (s) P,Tfound :
<P,T>voidrequired: void
doIt(null); ^
Note that if I replace the null parameter with a non-null value, it compiles fine.
Which of the compilers behaves correctly and why? Is this a bug of one of them?
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):
Further explorations
Using explicit type parameters "fixes" the problem:
To show that this has less to do with a
nullargument and more to do with the absolute lack of information for type inferrence, you can try e.g. either of the following declarations:In either case, an invocation
doIt();doesn’t compile injavac, as it must inferUto beObjectas 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