Java Bounded Generics:类型推断错误?(方法调用,JLS 15.12.2.7)

use*_*633 10 java generics type-inference compiler-errors jls

对于以下代码段:

import java.util.List;

public class Main {
    interface Interface1<T> {}
    interface Interface2<T> extends Interface1<T> {}
    static class Bound {}
    interface BoundedI1<T extends Bound> extends Interface1<T> {}
    interface BoundedI2<T extends Bound> extends Interface2<T> {}

    public static void main(String[] args) {
        test((List<BoundedI2<?>>) null);
        //test2((List<BoundedI2<?>>) null);
    }

    public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }

    public static void test2(List<? extends Interface1<? extends Bound>> list) {}
}
Run Code Online (Sandbox Code Playgroud)

第一次调用时编译器正常,但如果我取消注释第二次调用,则会抱怨.这是类型推理系统中的错误,还是有人可以解释为什么JLS中的推理规则在这里失败?

在6u43和7u45 Oracle JDK上进行了测试.

更新:似乎eclipsec接受它就好了.不幸的是我无法真正改变我们的工具链:P,但在编译器中找到差异很有意思.

错误消息,由ideone打印(很酷的工具顺便说一句):

Main.java:12: error: method test2 in class Main cannot be applied to given types;
        test2((List<BoundedI2<?>>) null);
        ^
  required: List<? extends Interface1<? extends Bound>>
  found: List<BoundedI2<?>>
  reason: actual argument List<BoundedI2<?>> cannot be converted to List<? extends Interface1<? extends Bound>> by method invocation conversion
Run Code Online (Sandbox Code Playgroud)

更新2:这编译很好,这表明编译器确实认为BoundedI2<?>是可分配的Interface1<? extends Bound>,这似乎更直接与JLS相矛盾:

public class Main {
    interface Interface1<T> {}
    interface Interface2<T> extends Interface1<T> {}
    static class Bound {}
    interface BoundedI1<T extends Bound> extends Interface1<T> {}
    interface BoundedI2<T extends Bound> extends Interface2<T> {}

    public static void main(String[] args) {
        test((List<BoundedI2<?>>) null);
        //test2((List<BoundedI2<?>>) null);
        test3((BoundedI2<?>) null);
    }

    public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }

    public static void test2(List<? extends Interface1<? extends Bound>> list) {}
    public static void test3(Interface1<? extends Bound> instance) {}
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*las 1

看起来命令行编译器同时处理有些困难

  • 事实上,BoundedI2 在 T 上是通用的,它必须是“Bound”
  • Interface2 正在扩展 Interface1

至少没有正确实例化 BoundedI2 。确实奇怪的是,在同一个 JDK 上配置的 Eclipse 可以很好地编译它...请注意,Eclipse 使用它的内部编译器来处理您键入时的增量重新计算,因此它根本不会调用 JDK 的编译器(请参阅 org/ eclipse/jdt/internal/编译器包)。

通过强制 BoundedI2 使用具体类型而不是类型推断,此修改使其在 Eclipse 和命令行中都可以正常编译:

import java.util.List;

public class PerfTest {
    interface Interface1<T> {}
    interface Interface2<T> extends Interface1<T> {}
    static class Bound {}
    interface BoundedI1<T extends Bound> extends Interface1<T> {}
    interface BoundedI2<T extends Bound> extends Interface2<T> {}
    static class Actual extends Bound {}

    public static void main(String[] args) {
        test((List<BoundedI2<Actual>>) null);
        test2((List<BoundedI2<Actual>>) null);
    }

    public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }

    public static void test2(List<? extends Interface1<? extends Bound>> list) {}
}
Run Code Online (Sandbox Code Playgroud)