在 Java 7 中使用方法重载时,为什么自动装箱不会推翻可变参数?

问题描述 投票:0回答:3

我们的 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 everyting 下使用 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。 那么为什么 自动装箱不会在这里否决可变参数吗?

Eclipse(使用来自 eclipse.org 的 tar.gz 安装)编译它: 不管是否安装 OpenJDK 6。

非常感谢您的帮助!

编辑:

在这两种情况下,编译器都会获得选项

source="1.6"
target="1.6"
。 Eclipse 编译注释只是作为注释。

java overloading variadic-functions autoboxing
3个回答
17
投票

我猜这与 bug #6886431 有关,该 bug 似乎也在 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) { ... } 

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

进入您的新解决方案。


0
投票

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

即使它在规范中,你的代码的读者也不会通过语言律师来了解,所以你需要对其进行评论来解释,他们可能会也可能不会阅读评论。 他们甚至可能不会考虑其中一种替代方案 - 只是看到一种适合的重载,然后运行它。 一场事故即将发生。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.