下面的代码用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:不兼容的类型;推断类型参数
java.lang.Number、java.lang.Object 不符合类型边界
变量 P,T
发现:
无效
必填:无效
doIt(null);
^
请注意,如果我用非空值替换空参数,它可以正常编译。
哪个编译器的行为正确,为什么?这是其中之一的错误吗?
The following code compiles perfectly with Eclipse, but fails to compile with javac:
public class HowBizarre {
public static <P extends Number, T extends P> void doIt(P value) {
}
public static void main(String[] args) {
doIt(null);
}
}
I simplified the code, so T is not used at all now. Still, I don't see a reason for the error.
For some reason javac decides that T stands for Object, and then complains that Object does not conform to the bounds of T (which is true):
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>
void
required: void
doIt(null);
^
Note that if I replace the null parameter with a non-null value, it compiles fine.
Which of the compilers behaves correctly and why? Is this a bug of one of them?
发布评论
评论(3)
该问题是由于 JLS 规范要求必须将其他不可推断的类型参数推断为
Object
,即使它不满足边界(并因此触发编译错误)。以下是“bug”报告的摘录(为了清晰起见,已对其进行了进一步注释):
进一步探索
使用显式类型参数“修复”问题:
表明这与
null
参数关系不大,并且更多与绝对缺乏类型推断信息有关,您可以尝试以下任一声明:在任何一种情况下,调用
doIt();
都不会在javac< 中编译/code>,因为它必须根据 15.12.2.8 推断
U
为Object
,即使这样做会触发编译错误。关于 Eclipse 的注意事项
虽然上面的代码片段都不能在某些版本的 javac 中编译,但它们都可以在某些版本的 Eclipse 中编译。这表明 Eclipse 方面存在错误。众所周知,不同的编译器之间存在分歧。
相关问题
The problem is due to a JLS specification that mandates that otherwise uninferrable type arguments must be inferred as
Object
, even if it doesn't satisfy the bounds (and would consequently trigger a compilation error).The following is an excerpt from the "bug" report (which has been further annotated for clarity):
Further explorations
Using explicit type parameters "fixes" the problem:
To show that this has less to do with a
null
argument and more to do with the absolute lack of information for type inferrence, you can try e.g. either of the following declarations:In either case, an invocation
doIt();
doesn't compile injavac
, as it must inferU
to beObject
as per 15.12.2.8, even if doing so would trigger a compilation error.Note on Eclipse
While none of the snippets above compile in some version of
javac
, they all do in some version of Eclipse. This would suggest a bug on Eclipse's part. It's been known that there are disagreements between the different compilers.Related questions
这是javac 中的一个错误。 Eclipse推断正确的类型。
你可以通过调用 doIt((Number) null); 来
解决这个问题。即使你不打算使用 javac 进行开发,也可以解决这个问题,因为像 ant 或 maven 这样的工具会使用它,并且它会如果您在某个时候引入它们,则会出现问题。
It's rather a bug in javac. Eclipse infers the correct type.
You can work it around by calling
doIt((Number) null);
Even if you don't plan to use javac for development, fix this issue, because tools like ant or maven use it and it will cause problems in case you introduce them at some point.
根据 Polygenelubricants 的研究,sun 的 javac 显然符合规范。过去我也使用过其他编译器,当出现冲突时,结果总是sun的javac是正确的。 Sun 的优势在于将他们从实施过程中获得的经验记录到规范中,而其他人则必须从头开始阅读规范 - 当您阅读它时,真的很难不入睡。
from polygenelubricants' research, sun's javac is apparently faithful to the spec. in the past I also used other compilers and when there's a conflict, it always turned out that sun's javac is correct. Sun has the advantage of documenting their experience from implementation into the spec, while the other guys have to read the spec from scratch - it is really hard not to fall in sleep when you read it.