我们的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。所以为什么 在这里不会自动代替varargs吗?
Eclipse(使用eclipse.org中的tar.gz安装)编译没有 如果安装了OpenJDK 6则无关紧要。
非常感谢你的帮助!
修改
在两种情况下,编译器都会获得选项source="1.6"
和target="1.6"
。 Eclipse编译注释仅用作注释。
答案 0 :(得分:17)
我猜这与bug #6886431有关,似乎也在OpenJDK 7中修复了。
问题在于JLS 15.12.2.5 Choosing the Most Specific Method 当前者的形式参数的类型是后者的形式参数的子类型时,一种方法比另一种方法更具体。
由于int
不是Object
的子类型,因此您的方法都不是最具体的,因此您的调用不明确。
但是,可以采用以下解决方法,因为Integer
是Object
的子类型:
public void log(Level logLevel, Object... args) { ... }
public void log(Level logLevel, Integer value, Object... args) { ... }
答案 1 :(得分:2)
Eclipse使用它自己的编译器,因此Eclipse最终遵循SUN / Oracle提供的编译器所做的事情;但是,有时候(就像在这种情况下)存在差异。
这可能“走向任何一种方式”,可能在Java 6中,问题没有得到详细解决。由于Java强烈要求减少其环境中“模糊”含义的数量(在许多平台上强制执行相同的行为),我认为它们在7版本中收紧(或直接指定)已决定的行为。 / p>
您刚刚陷入新规范澄清的“错误”方面。对不起,但我想你会写一点这个
public void log(Level logLevel, Object... args) {
if (args != null && args[0] instanceof Integer) {
// do something else
} else {
// do something
}
}
进入新的解决方案。
答案 2 :(得分:0)
这是一种比谨慎更接近边缘的滑冰方式。除非你能在规范中找到关于行为的清晰语言,否则我会避免像这样模糊不清。
即使规范中的 ,您的代码的读者也不会知道语言律师,因此您需要对其进行评论以解释,他们可能会也可能不会阅读评论。他们甚至可能不会考虑其中一种替代方案 - 只需看一个适合的超载,然后运行即可。事故等待发生。