为什么推断泛型类型在这里不起作用?

时间:2013-06-13 17:07:40

标签: java generics

假设我有以下类:

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.7编译器(javac 1.7.0_21)和
  • Oracle 1.6编译器(javac 1.6.0_37)

在第二个例子中都可以正常工作。

但是:这是OpenJDK 1.6编译器中的错误还是Java语言规范中的歧义?

1 个答案:

答案 0 :(得分:3)

参数类型在第二个示例中没有以任何方式提及S.编译器告诉你它因此无法推断它。

详细说明。在第一个示例中,您要求Class<? extends MyT<S, T>>。在test()中,您可以给它Class<MyTImpl>。当编译器检查边界时,它会将MyT<S, T>MyTImpl匹配,并发现MyTImpl实现了MyT<MySImpl, MyTImpl>,因此它可以推断出MySImpl S只需将这两件事放在一边,就可以MyTImpl T

然后检查STMySImplMyTImpl的约束,这些约束成功。

在第二个示例中,您要求Class<T>。编译器看到Class<MyTImpl>,为MyTImpl推断T,并完成。如果没有推断S,就会出错。

T的约束检查,可以提供S的信息,但不会发生。