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

时间:2011-10-07 15:25:19

标签: java compiler-construction overloading variadic-functions autoboxing

我们的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编译注释仅用作注释。

3 个答案:

答案 0 :(得分:17)

我猜这与bug #6886431有关,似乎也在OpenJDK 7中修复了。

问题在于JLS 15.12.2.5 Choosing the Most Specific Method  当前者的形式参数的类型是后者的形式参数的子类型时,一种方法比另一种方法更具体。

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

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

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)

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

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