在Java 7中使用方法重载时,为什么autoboxing不会覆盖varargs?

我们的Java项目中有一个类LogManager,如下所示:

public class LogManager { public void log(Level logLevel, Object... args) { // do something } public void log(Level logLevel, int value, Object... args) { // do something else } } 

在Debian下使用OpenJDK 6编译项目时,每个工作都很好。 使用OpenJDK 7时 ,构建(使用ant完成)会产生以下错误,并且构建失败:

 [javac] /…/LogManager.java:123: error: reference to log is ambiguous, both method log(Level,Object...) in LogManager and method log(Level,int,Object...) in LogManager match [javac] log(logLevel, 1, logMessage); [javac] ^ [javac] /…/SomeOtherClass.java:123: error: reference to log is ambiguous, both method log(Level,Object...) in LogManager and method log(Level,int,Object...) in LogManager match [javac] logger.log(logLevel, 1, logMessage); [javac] ^ 

只要1不是自动装箱,方法调用应该是明确的,因为1是一个int并且不能向上转换为Object。 那么为什么autoboxing不会在这里推翻varargs?

Eclipse(使用eclipse.org中的tar.gz安装)无论是否安装了OpenJDK 6,都会编译它。

非常感谢你的帮助!

编辑:

在两种情况下,编译器都获得选项source="1.6"target="1.6" 。 Eclipse编译注释仅用作注释。

我想这与bug #6886431有关 ,它似乎也在OpenJDK 7中得到修复。

问题在于JLS 15.12.2.5选择最具体的方法表明,当前者的forms参数的类型是后者的forms参数的子类型时,一种方法比另一种方法更具体。

由于int不是Object的子类型,因此您的方法都不是最具体的,因此您的调用是不明确的。

但是,可以使用以下解决方法,因为IntegerObject的子类型:

 public void log(Level logLevel, Object... args) { ... } public void log(Level logLevel, Integer value, Object... args) { ... } 

Eclipse使用它自己的编译器,因此Eclipse最终遵循SUN / Oracle提供的编译器所做的事情; 然而,有时(就像在这种情况下)存在差异。

这可能“走向任何一种方式”,可能在Java 6中,问题没有得到详细解决。 由于Java强烈要求减少其环境中“模糊”含义的数量(在许多平台上强制执行相同的行为),我认为它们在7版本中收紧(或直接指定)已决定的行为。

您刚刚陷入新规范澄清的“错误”方面。 对不起,但我想你会写一点这个

 public void log(Level logLevel, Object... args) { if (args != null && args[0] instanceof Integer) { // do something else } else { // do something } } 

进入你的新解决方案。

这是一种比谨慎更接近边缘的滑冰方式。 除非你能在规范中找到关于行为的清晰语言,否则我会避免这样的含糊不清。

即使它符合规范,您的代码的读者也不会完成语言律师的知识,因此您需要对其进行评论以解释,并且他们可能会也可能不会阅读评论。 他们甚至可能不会考虑其中一种替代方案 – 只需看一个适合的超载,然后运行即可。 等待发生的事故。