下面的代码可以用 Eclipse 完美编译,但是不能用 javac 编译:
public class HowBizarre {
public static <P extends Number, T extends P> void doIt(P value) {
}
public static void main(String[] args) {
doIt(null);
}
}
我简化了代码,所以现在根本不用 T。不过,我看不出错误的原因。 出于某种原因,javac 决定 T 代表 Object,然后提示 Object 不符合 T 的边界(这是真的):
HowBizarre.java:6: incompatible types; inferred type argument(s) java.lang.Number,java.lang.Object do not conform to bounds of type variable (s) P,T
found :
<P,T>
voidrequired: void
doIt(null); ^
请注意,如果我将 null 参数替换为非 null 值,它可以正常编译。
哪个编译器的行为正确,为什么?这是其中之一的错误吗?
最佳答案
问题是由于 JLS 规范规定,否则无法推断的类型参数必须推断为 Object
,即使它不满足边界(并因此触发编译错误)。
以下是“错误”报告的摘录(为清楚起见,对其进行了进一步注释):
"Bug" ID 6299211 - method type variable: inference broken for null
This program does not compile:
public class Try { void m() { java.util.Collections.max(null); } }
State: CLOSED, NOT A DEFECT.
Evaluation: THIS IS NOT A BUG. The inference algorithm cannot gather any information from the argument (
null
) and the method is not called in a place where there are any expectations on the returned value. In such cases the compiler must inferjava.lang.Object
for the type variable.
JLS 15.12.2.8 Inferring Unresolved Type Arguments
Any remaining type variables that have not yet been inferred are then inferred to have type
Object
However,
Object
is not a subtype ofComparable<? super Object>
and thus not within the bounds of the type variable in the declaration ofCollections.max
:
<T extends
Object & Comparable<? super T>
> T max(Collection<? extends T>)
进一步探索
使用显式类型参数“修复”了这个问题:
HowBizarre.<Number,Integer>doIt(null); // compiles fine in javac
表明这与 null
关系不大参数和更多与类型推断信息的绝对缺乏有关,您可以尝试例如以下任一声明:
<T,U extends Comparable<T>> void doIt()
<T extends Number,U extends T> void doIt()
无论哪种情况,调用 doIt();
不在 javac
中编译,因为它必须推断出 U
成为Object
根据 15.12.2.8,即使这样做会触发编译错误。
Eclipse 注释
虽然上面的代码片段都无法在某些版本的 javac
中编译,它们都在某些版本的 Eclipse 中执行。这表明 Eclipse 部分存在错误。众所周知,不同的编译器之间存在分歧。
相关问题
关于java - 编译器对泛型方法的空参数的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3000177/