Are you sure? My test is that the 1st m(cInteger, cInteger)
fails, and the 2nd m(cSomething, cSomething)
is ok. Also the raw m(x,x)
doesn't compile.
(1) m(cInteger,cInteger)
fails
Both m() match the arguments; for m2, inference yields S=U=Class<Integer>
.
Now the question is, is m1 more specific than m2? Following the procedure in 15.12.2.5, it is. If that is the case, there is no ambiguity; m1 should be picked as the most specific method, and the call should compile.
However, this violates the informal requirement given by the spec: if m1 is more specific than m2, any invocation handled by m1 could be passed on to m2 without a compile-time type error. For example, m1 can accept arguments (Class<Integer>,Class<String>)
, which m2 can't (due to the less-than-perfect type inferrence
procedure).
Javac obviously adhere to the informal notion; this is probably because the formal spec has a bug - it should have included capture conversion (explained later) in the definition of more specific relation; then m1 is not more specific than m2, therefore the call m(cInteger,cInteger)
is ambiguous.
If another compiler strictly adheres to the formal spec, it's not its fault to inherit the spec's bug.
(2) m(x, x)
fails
for the same reason as (1); both methods match, but neither is more specific than the other.
m1 matches through method invocation conversion, which allows unchecked conversion from raw Class
to Class<?>
. m2 matches after inferring S=U=Class
(3) m(cSomething, cSomething)
compiles
This is because m1 is the only applicable one, there is therefore no ambiguity.
m2 is not applicable, let's see why.
First, the types of the arguments are not exactly (Class<?>,Class<?>)
- capture conversion is applied on them first. (Again, the spec is very unclear (see chapter 15), but I'm very certain that this is well understood to be the case; the type of any expression is applied with capture conversion)
So the arguments types are (Class<X1>,Class<X2>)
, with two fresh type variables. There's another screwup here, a more precise conversion would've been (Class<X1>,Class<X1>)
, unfortunately, capture conversion is applied twice, indepedently, yeilding two different types.
m1 easily matches the argument types. But m2 doesn't match, due to the less-than-perfect type inference procedure. The procedure first yields that S=Class<X1>, U=Class<X2>
, after which, bounds of type variables are checked, where U extends S
fails.
(4) removing U's bound
Now (1),(2),(3) all compile. Because without U extends S
, inference passes.
For (1) and (2), m1 is now more specific than m2, no longer ambiguity.
For (3), m2 now matches; but then is shadowed by the more specific m1