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