使用可变长度参数进行Java重载

时间:2014-12-15 11:50:42

标签: java overloading

为什么此代码中没有编译错误:

public class OverloadingVarArgs
{
    public void fun1(int... b)
    {
        System.out.println("int");
    }
    public void fun1(long... a)
    {
        System.out.println("long");
    }
    public static void main(String[] args)
    {
        OverloadingVarArgs obj = new OverloadingVarArgs();
        obj.fun1();
    }

}

但是这段代码给出了编译错误!

public class OverloadingVarArgs
{
    public void fun1(int... b)
    {
        System.out.println("int");
    }
    public void fun1(boolean... a)
    {
        System.out.println("boolean");
    }
    public static void main(String[] args)
    {
        OverloadingVarArgs obj = new OverloadingVarArgs();
        obj.fun1();
    }
}

我认为在这两种情况下都应该存在编译错误,但事实并非如此。

3 个答案:

答案 0 :(得分:9)

选择正确的重载方法的规则如下:

  • 原始扩展使用可能的最小方法参数
  • 包装类型不能加宽到另一种包装类型
  • 您可以从int到Integer并将其扩展为Object但不会为Long
  • 加宽节拍拳击,拳击比赛。
  • 你可以选择Box然后加宽(一个int可以通过整数成为对象)
  • 你不能加宽然后Box(一个int不能变长)
  • 你无法将var-args与扩展或装箱结合起来

看看最后一条规则。您可以将扩展或装箱与可变长度参数组合使用。这意味着不能以任何方式操纵类型,您必须按原样执行比较。可以比较intlong,没问题,编译器可以推断int是两者中较小的一个。按照第一条规则,它将使用最小的方法参数,因此它已经计算出一个方法的正确(和唯一)路径。

但是,当你到达booleanint时,由于Java的强类型,两者之间不存在比较方法。由于不知道哪种类型最小,编译器完全不知道你指的是哪种方法。

更多视觉示例

让我们从编译器的角度一步一步地看待它。首先,使用intlong

int和long

步骤1 - 检查参数是否与任何参数匹配,如果是,那么它与哪个参数完全匹配

好吧,varargs表示您可以将0传递给多个参数。在这种情况下,您已选择传递0个参数,因此您的通话符合int类型和long类型。

第2步 - 尝试自动装箱或加宽。这应该有助于确定哪一个

您正在使用varargs,因此编译器知道根据最终规则它无法执行此操作。

第3步 - 尝试确定哪种类型最小

编译器能够将类型int与类型long进行比较。由此可知,int是最小的类型。

第4步 - 拨打电话

知道int是最小的类型,然后它将值传递给方法执行。

好的,现在让我们对booleanint做同样的事情。

布尔和int

步骤1 - 检查参数是否与任何参数匹配,如果是,那么它与哪个参数完全匹配

同样的故事。你没有通过任何东西,所以匹配两个参数。

第2步 - 尝试自动装箱或加宽。这应该有助于确定哪一个

如上所述,由于您使用了varargs,因此不允许这样做。

第3步 - 尝试确定哪种类型最小

这是至关重要的区别。这里的类型可比较。这意味着编译器不知道您希望通过最小类型的参数调用哪个方法。因此,它无法找到正确的路线。

第4步 - 拨打电话

如果不知道要调用哪个方法,它就无法继续执行并抛出相应的异常。

答案 1 :(得分:5)

在第二个示例中,编译器无法确定要调用的最具体的方法

血腥细节在the language spec中解释,但基本上如果比较两个变量(var-arg)方法,那么如果方法A可以接受传递给方法B的参数,而不是其他方式周围,​​然后方法B是最具体的。

在您的第一个示例中,应用rules of primitive sub-typing,即:

  

double> 1 float

     

浮动> 1 long

     

long> 1 int

     

int> 1 char

     

int> 1 short

     

短> 1 字节

     

其中> 1 表示'的直接超类型)

我们可以看到intlong更具体,因此选择了fun1(int... b)方法。

在第二个示例中,编译器在intboolean之间进行选择。这些原始类型之间没有子类型关系,因此没有最具体的方法,“方法调用不明确,发生编译时错误。”(15.12.2.5中的最后一行) )。

答案 2 :(得分:4)

当您拥有intlong(可比类型)时,默认情况下将使用最小值,即int(因为您没有传递参数) - 我认为这是因为int 可以扩展到longlong不能(除非你显式强制转换它) ,编译器将选择最低精度类型。

但是当你有booleanint时,无法进行比较并且你会得到

The method fun1(int[]) is ambiguous for the type OverloadingVarArgs