我们在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 everything下使用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没有自动装箱,方法调用就应该自动装箱是int型,不能向上转换为Object。那么,为什么这里的自动装箱不排除变量吗?
Eclipse(使用来自eclipse.org的tar.gz安装)不会编译它
非常感谢你的帮助!编辑:编译器在两种情况下都获得source="1.6"
和target="1.6"
选项。Eclipse编译注释只是一个注释。
我猜这与错误#6886431有关,似乎在OpenJDK 7中也得到了修复。
问题是JLS 15.12.2.5选择最具体的方法说明当一种方法的形式参数类型是后者的形式参数的子类型时,一种方法比另一种方法更具体。
由于int
不是Object
的子类型,所以你的两个方法都不是最具体的,因此你的调用是模糊的。
但是,由于Integer
是Object
的子类型,下面的解决方法是可能的:
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
}
}
这样滑离边缘太近了。除非你能在规范中找到关于行为的清晰语言,否则我会避免出现这种模棱两可的情况。
即使规范中是,你代码的读者也不会知道,所以你需要注释来解释,他们可能会也可能不会阅读注释。他们甚至可能不会考虑其中一个替代方案——只是看到一个适合的过载,然后运行它。事故即将发生