Java有界泛型:类型推断错误? (方法调用,JLS 15.12.2.7)

有关以下代码片段:
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) {}
}

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

测试了6u43和7u45 Oracle JDK.

更新:似乎像eclipsec接受它很好.不幸的是,我不能真正改变我们的工具链:P,但有兴趣的是在编译器中找到差异.

由ideone(酷工具btw)打印出来的错误信息:

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

更新2:这编译好,这表明编译器认为BoundedI2<?>可分配给Interface1扩展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) {}
}

解决方法

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

> BoundedI2在T上是通用的事实,它必须是“绑定”
> Interface2扩展Interface1的事实

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

这个修改使得它可以在Eclipse和命令行中编译,通过强制BoundedI2是一个具体的类型,而不是类型推断:

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) {}
}

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...