假设我有以下类:
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> {
}
我可以构建以下测试用例,该编译器在没有任何警告的情况下成功编译并运行:
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();
}
}
好的,好的。但我预计这会产生相同的效果:
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();
}
}
但是,这是一个编译错误:
S的无效推断类型;推断类型不符合 声明的界限推断:MySImpl bound(s):MyS
为什么会这样?
更新
我注意到该行为依赖于编译器。我使用OpenJDK 1.6编译器(javac 1.6.0_27)来编译代码。它打破了。但是:
在第二个例子中都可以正常工作。
但是:这是OpenJDK 1.6编译器中的错误还是Java语言规范中的歧义?
答案 0 :(得分:3)
参数类型在第二个示例中没有以任何方式提及S.编译器告诉你它因此无法推断它。
详细说明。在第一个示例中,您要求Class<? extends MyT<S, T>>
。在test()
中,您可以给它Class<MyTImpl>
。当编译器检查边界时,它会将MyT<S, T>
与MyTImpl
匹配,并发现MyTImpl
实现了MyT<MySImpl, MyTImpl>
,因此它可以推断出MySImpl
S
只需将这两件事放在一边,就可以MyTImpl
T
。
然后检查S
和T
对MySImpl
和MyTImpl
的约束,这些约束成功。
在第二个示例中,您要求Class<T>
。编译器看到Class<MyTImpl>
,为MyTImpl
推断T
,并完成。如果没有推断S
,就会出错。
T
的约束检查,可以提供S
的信息,但不会发生。