问题
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?
回答1:
Strictly according to the spec, T
cannot be inferred (per 15.12.2.7), so it should be taken as Object
.
This can be viewed as a failure of the spec. This is how spec infers R
: first there is constraint R :> BigDecimal
, where :>
means is a supertype of. The inference rules then choose R=BigDecimal
since it's the most specific type satisfying the constraint.
Now, since T:>R
, T:>BigDecimal
, one would think this should yield T=BigDecimal
too.
Unfortunately the inference rules do not take T:>R
into account. There is no contraint on T
. 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.
来源:https://stackoverflow.com/questions/8660316/type-inference-more-restrictive-in-jdk-7-than-jdk-6