19

我们的 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。那么为什么自动装箱不在这里推翻可变参数呢?

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

非常感谢你的帮助!

编辑:

编译器source="1.6"target="1.6"这两种情况下都可以选择。Eclipse 编译说明仅作为注释。

4

3 回答 3

17

我猜这与错误#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) { ... } 
于 2011-10-07T15:57:29.597 回答
2

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
    }
}

进入您的新解决方案。

于 2011-10-07T15:37:52.703 回答
0

这比谨慎的滑冰方式更接近边缘。除非你能在规范中找到关于行为的清晰语言,否则我会避免任何像这样模棱两可的事情。

即使它规范中,您的代码的读者也不会通过语言律师了解,因此您需要对其进行评论以进行解释,他们可能会或可能不会阅读评论。他们甚至可能不会考虑其中一种替代方案——只看到一个适合的重载,然后运行它。等待发生的事故。

于 2011-10-07T16:11:47.770 回答