Java 重载:对调用的引用不明确

Java overloading: reference to call ambiguous

考虑以下示例代码:

public class TestClass {

    public void doSth(String str, String l, Object... objects) {
        System.out.println("A");
    }

    public void doSth(String str, Object... objects) {
        System.out.println("B");
    }

}

当我现在调用 new TestClass().doSth("foo", "bar") 时,我得到了预期的结果 A。但是,如果我通过将参数 l 更改为原始类型来更改第一个方法的方法签名:

public class TestClass {

    public void doSth(String str, long l, Object... objects) {
        System.out.println("A");
    }

    public void doSth(String str, Object... objects) {
        System.out.println("B");
    }

}

调用 new TestClass().doSth("foo", 2L) 将产生 reference to call ambiguous 编译时错误。

我考虑了一段时间,也咨询了 this Whosebug question,但我无法理解为什么会这样。在我看来,doSth("foo", 2L) 更具体到 doSth(String string, long l, Object... obj) 签名,应该允许编译器也得出这个结论。

在这种情况下,自动装箱会让您很伤心。具有讽刺意味的是,在那之前你是对的 - "long" 版本很容易被选中。

基本上,编译器知道它可以从您的值创建一个 Long,当然,它是一个对象。所以它仍然很困惑,因为可以使用长版本或长版本。一个 "better" 比另一个好吗?也许吧,但这是一条很好的线。

在这种情况下,我只能报告我的观察结果,而不是关于为什么 Java 如此表现的确切论证。

首先,将方法更改为

void doSth(long l) {...}
void doSth(Object o) {...}

解决了这个问题,即 doSth(2L); 将产生预期的结果。

更进一步,将方法参数更改为可变参数

void doSth(long... ls) {...}
void doSth(Object... os) {...}

与调用 doSth(2l); 一起产生与 OP 报告的相同的编译错误。

现阶段我的建议是将参数封装到数组中,再加上自动装箱会造成破坏。我对 JLS 的了解还不够充分,无法正确解释这一点。