如果我们采用以下类,它们在JDK 6下编译正确:
public final class Foo<V> {
private final V value;
private Foo(final V value) {
this.value = value;
}
public static <T, R extends T> Foo<T> of(final R value) {
return new Foo<T>(value);
}
}
final class Tester {
@Test(groups="unit")
public static void test() {
bar(Foo.of(BigDecimal.ZERO)); // This line fails in JDK 7 but not JDK 6
}
private static void bar(final Foo<? extends Number> target) {
assert target != null;
}
}
但是,在JDK 7下,我收到以下错误:
[ERROR] \work\fsb-core\src\test\java\com\fsb\core\Foo.java:[42,8] error:
method bar in class Tester cannot be applied to given types;
我认为类型推断在JDK 7中的限制性较小(例如,添加构造函数推断)。但是,这里,编译器拒绝在JDK 6下有效的类型。
这是一个错误吗?或者推理的规则是否对方法更加严格?
答案 0 :(得分:3)
严格按照规范,T
无法推断(按照15.12.2.7),因此应将其视为Object
。
这可以视为规范的失败。这就是规范推断R
的方式:首先是约束R :> BigDecimal
,其中:>
表示是的超类型。然后推理规则选择R=BigDecimal
,因为它是满足约束的最具体类型。
现在,由于T:>R
,T:>BigDecimal
,人们会认为这也应该产生T=BigDecimal
。
不幸的是,推理规则不会考虑T:>R
。 T
没有任何约束。 T
不是通过相同的原则推断的。
虽然很糟糕,但规格是规格。你的代码不应该编译。那里的Javac6错了。
在Java 8中,推理规则有了很大改进,使lambda表达式更易于使用。希望您的代码应该在Java 8中编译。