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

Java重载:调用的引用不明确,java,overloading,primitive,jls,Java,Overloading,Primitive,Jls,考虑以下示例代码: 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"); } } 当我现在调用newte

考虑以下示例代码:

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");
    }

}
当我现在调用
newtestclass().doth(“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");
    }

}
调用
newtestclass().doth(“foo”,2L)
将产生一个
引用来调用不明确的编译时错误


我考虑了一段时间,也进行了咨询,但我无法理解为什么会发生这种情况。在我看来,
doSth(“foo”,2L)
更特定于
doSth(String String,long l,Object…obj)
签名,并且应该允许编译器也得出这个结论。

在这种情况下,自动装箱会让你感到悲伤。具有讽刺意味的是,在此之前,你是对的,“长”版本很容易被选择


基本上,编译器知道它可以从您的值中创建一个Long,当然,它是一个对象。因此,无论是长版本还是长版本都可能被使用,这仍然是一个困惑。一个比另一个好吗?也许吧,但这是一条很细的线。

在这种情况下,我只能报告我的观察结果,而不能确切地说明Java为什么会像它那样运行

第一,将方法更改为

void doSth(long l) {...}
void doSth(Object o) {...}
消除问题,即
doSth(2L)将产生预期的结果

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

void doSth(long... ls) {...}
void doSth(Object... os) {...}
连同调用
doSth(2l)产生与OP报告的编译错误相同的编译错误


我在这一阶段的建议是,将参数封装到数组中,再加上自动装箱会造成严重破坏。我对JLS的了解还不足以正确解释这一点。

显然,基本体也可以是对象?@blahfunk,是的,它们可能被包装起来。我想到的唯一解释是,但这应该比该方法的基本体“更远”一步。我不知道,但是在函数声明中将
long
更改为
long
为我解决了这个问题。看起来像是重复的:这些方法包含varargs参数,编译器需要进入第三阶段,试图很好地区分它们,在JLS中,明确指定在不允许装箱或拆箱转换的情况下执行重载解析。在这个阶段中,不进行自动装箱。看起来应该在该阶段选择
doSth(stringstr,longl,Object…objects)
。我错过什么了吗?这很有趣。当只有一个参数,即
doSth(long l)
doSth(Object o)
,这为什么不会造成大破坏?@Tunaki第1阶段和第2阶段也排除了可变算术方法,因此在第3阶段之前,OP的两种方法都不会被考虑。奇怪的是,
doSth(“foo”,2L,null)
将编译,因为第一个项目符号(在链接中)下的斜体注释说明了什么。