Reputation: 40840
Suppose I have the following classes:
interface MyS<T extends MyT<S, T>, S extends MyS<T, S>> {
}
interface MyT<S extends MyS<T, S>, T extends MyT<S, T>> {
}
public class MySImpl implements MyS<MyTImpl, MySImpl> {
}
public class MyTImpl implements MyT<MySImpl, MyTImpl> {
}
I can build the following testcase which compiles and runs successfully without any warning:
public class STTest {
@Test
public void test() throws Exception {
createInstance(MyTImpl.class);
}
public static<T extends MyT<S, T>, S extends MyS<T, S>> void createInstance(
final Class<? extends MyT<S, T>> beanClass) throws Exception {
final MyT<S, T> bean = beanClass.newInstance();
}
}
OK, fine. But I expected that this would have the identical effect:
public class STTest {
@Test
public void test() throws Exception {
createInstance(MyTImpl.class);
}
public static<T extends MyT<S, T>, S extends MyS<T, S>> void createInstance(
final Class<T> beanClass) throws Exception {
final T bean = beanClass.newInstance();
}
}
However, this is a compile error:
invalid inferred types for S; inferred type does not conform to declared bound(s) inferred: MySImpl bound(s): MyS
Why is this?
UPDATE:
I noticed that the behaviour is compiler dependent. I used the OpenJDK 1.6 compiler (javac 1.6.0_27) for compiling to code. And it breaks. However:
both work fine on the second example.
However: Is this a bug in the OpenJDK 1.6 compiler or is this an ambiguity in the Java language specification?
Upvotes: 4
Views: 130
Reputation: 72054
The argument type doesn't mention S in any way in the second example. The compiler is telling you that it therefore can't infer it.
To elaborate. In the first example, you ask for a Class<? extends MyT<S, T>>
. In test()
, you give it a Class<MyTImpl>
. As the compiler checks the bounds, it matches MyT<S, T>
against MyTImpl
and finds that MyTImpl
implements MyT<MySImpl, MyTImpl>
, so it can infer MySImpl
for S
and MyTImpl
for T
by simply placing those two things alongside.
Then it checks the constraints on S
and T
for MySImpl
and MyTImpl
, which succeeds.
In the second example, you ask for a Class<T>
. The compiler sees Class<MyTImpl>
, infers MyTImpl
for T
, and is done. Failing to infer S
, it errors out.
Constraint checking for T
, which could provide the information what S
is, doesn't happen.
Upvotes: 3