4

假设我有以下课程:

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 界限: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 语言规范中的歧义?

4

1 回答 1

3

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

详细说明。在第一个示例中,您要求一个Class<? extends MyT<S, T>>. 在test(),你给它一个Class<MyTImpl>。当编译器检查边界时,它会匹配MyT<S, T>MyTImpl找到MyTImplimplements MyT<MySImpl, MyTImpl>,因此它可以通过简单地将这两个东西放在一起来推断MySImplforSMyTImplfor 。T

然后它检查 和 上的约束和,S它成功了。TMySImplMyTImpl

在第二个示例中,您要求一个Class<T>. 编译器看到、Class<MyTImpl>推断并完成。无法推断,它会出错。MyTImplTS

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

于 2013-06-13T17:11:11.210 回答