以下是代码片段:
编译器可以接受第一个调用,但是如果我取消注释第二个调用,编译器就会报错。这是类型推断系统的一个bug吗?还是有人能够解释一下为什么JLS中的推断规则在这里失败了?
在Oracle JDK 6u43和7u45上进行了测试。
更新:似乎eclipsec可以很好地接受它。不幸的是,我不能真正改变我们的工具链:P,但发现编译器之间的差异很有趣。
错误消息(由ideone打印):
对于以下的代码块:
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) {}
}
编译器可以接受第一个调用,但是如果我取消注释第二个调用,编译器就会报错。这是类型推断系统的一个bug吗?还是有人能够解释一下为什么JLS中的推断规则在这里失败了?
在Oracle JDK 6u43和7u45上进行了测试。
更新:似乎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
更新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) {}
}
javac
编译它时,我确实遇到了一个错误:test2 (java.util.List<? extends Main.Interface1<? extends Main.Bound>>) in Main cannot be applied to (java.util.List<Main.BoundedI2<?>>)
。我已经双重检查了Eclipse使用的路径,以确保它是相同的编译器。这非常有趣。 - azurefrog<?>
替换为<? extends Bound>
不会引发错误。可能推断规则不考虑多个推断类型的"组合",但我对规则不够熟悉,无法确定是否如此。另外一个问题是,我不确定<?>
应该正确地被视为<? extends Object>
还是<? extends Bound>
,但那是另一个问题... - awksptest()
不应该编译,因为List <BoundedI2 <?>>
不能赋值给List <? extends Interface2 <? extends Bound>>
吗?具体来说,BoundedI2
扩展了Interface2
,但是<?>
不是<? extends Bound>
。我错过了什么吗?如果定义BoundedI2
为<T extends Bound>
,那么编译器是否足够聪明,知道<?>
应该是<? extends Bound>
?这甚至是一个有效的主张吗? - awksp