JDK 7 中的类型推断比 JDK 6 中的限制更多?
我认为这可能与 为什么列表的泛型转换<?扩展集..>到列表<设置..>在 Sun JDK 6 上成功,但在 Oracle JDK 7 上编译失败?
如果我们使用以下类,它们在 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 下有效的类型。
这是一个错误吗?或者推理规则对方法是否更加严格?
I think this might be related to Why does a generic cast of a List<? extends Set..> to List<Set..> succeed on Sun JDK 6 but fail to compile on Oracle JDK 7?
If we take the following classes, they compile fine under 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;
}
}
However, under JDK 7, I receive the following error:
[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;
I thought type inference was less restrictive (e.g., adding constructor inference) in JDK 7. However, here, the compiler is rejecting a type that is valid under JDK 6.
Is this a bug? Or were the rules on inference made more stringent for methods?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
严格根据规范,无法推断
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 中编译。
Strictly according to the spec,
T
cannot be inferred (per 15.12.2.7), so it should be taken asObject
.This can be viewed as a failure of the spec. This is how spec infers
R
: first there is constraintR :> BigDecimal
, where:>
means is a supertype of. The inference rules then chooseR=BigDecimal
since it's the most specific type satisfying the constraint.Now, since
T:>R
,T:>BigDecimal
, one would think this should yieldT=BigDecimal
too.Unfortunately the inference rules do not take
T:>R
into account. There is no contraint onT
.T
is not inferred through the same principle.While it sucks, spec is spec. Your code should not compile. Javac6 is wrong there.
In Java 8 there's an great improvement on inference rules to make lambda expression easier to use. Hopefully your code should compile in Java 8.