Varargs Java不明确调用

Varargs Java不明确调用,java,methods,overloading,variadic-functions,Java,Methods,Overloading,Variadic Functions,我对Java的varargs方法有点困惑: 当我试图在不传递任何参数的情况下调用sum()时,调用了方法的int版本。我不明白为什么;通常,编译器必须引发错误 相反,当我尝试在没有任何参数的情况下调用sum时,以下代码段会生成编译器错误: public static int sum(int ...a) { return 0; } public static boolean sum(boolean ...a) { return true; } 这里应用的一般规则是:如果一个方法

我对Java的varargs方法有点困惑:

当我试图在不传递任何参数的情况下调用
sum()
时,调用了方法的
int
版本。我不明白为什么;通常,编译器必须引发错误

相反,当我尝试在没有任何参数的情况下调用
sum
时,以下代码段会生成编译器错误:

public static int sum(int ...a) {
    return 0;
}

public static boolean sum(boolean ...a) {
    return true;
}

这里应用的一般规则是:如果一个方法签名严格地比另一个更具体,那么Java选择它时不会出错

直观地说,如果可以完全删除方法签名,则该方法签名更具体,而另一个不太具体的方法签名则适用于每个现有调用

当在签名
sum(int…args)
sum(double…args)
之间进行选择时,签名
sum(int…args)
更具体,因为该方法的任何调用也可以通过应用加宽转换传递给
sum(double…args)
。对于不能进行类似转换的
sum(boolean…args)
方法,情况并非如此

Java语言规范,SE 8版本:

15.12. 方法调用表达式 Java编程语言使用的规则是选择最具体的方法

对于参数表达式e1、…、ek的调用,如果以下任一项为真,则一个适用方法m1比另一个适用方法m2更具体:

  • m2不是泛型的,m1和m2通过严格或松散调用适用,其中m1具有形式参数类型S1,…,Sn,m2具有形式参数类型T1,…,Tn,对于所有i(1)的参数ei,类型Si比Ti更具体≤ 我≤ n、 n=k)

对于任何表达式,如果s1浮动,则类型S比类型T更具体

浮动>1长

长>1整数

如中所述,在选择使用哪个重载方法时,会遵循一些规则

引述:

  • 基元加宽使用尽可能小的方法参数
  • 包装类型不能扩展为其他包装类型
  • 您可以将整型框设置为整型框,并将其加宽为对象,但不能设置为长型框
  • 加宽比拳击快,拳击比Var args快
  • 您可以先装箱,然后加宽(整数可以通过整数变成对象)
  • 不能先加宽后加框(整数不能变长)
  • 不能同时使用加宽和装箱组合变量args
  • (让我们像这样重新定义规则1:“原语加宽尽可能使用最具体的方法参数。”)

    因此,牢记这些规则,我们可以了解这里发生了什么:

    根据第一条规则,基元加宽尽可能使用最具体的方法参数。由于
    int
    由一个非十进制数(例如
    1
    )表示,
    double
    由一个十进制数表示,其精度比
    float
    (例如
    1.0
    )高32字节,因此我们可以说
    int
    s“小于”或“小于”
    double
    s,并且根据该逻辑,
    int
    s可以“升级”到
    double
    s,而
    double
    s可以“降级”到
    int
    s

    简单地说,可以扩展到另一个原语的原语(例如,
    int
    ->
    float
    ->
    double
    )比另一个原语更具体。例如,
    int
    double
    更具体,因为
    1
    可以升级为
    1.0

    当您没有向这些同名的重载vararg方法传递任何参数时,由于返回值实际上是相同的(分别为0和0.0),编译器将选择使用接受类型为
    int
    的vararg的方法,因为它更具体

    因此,当您分别引入
    int
    s和
    boolean
    s(不能相互加宽的类型)的相同方法时,编译器现在无法选择要使用的方法,因为
    int
    s不能像
    int
    s、
    float
    s和
    double
    s那样“升级”或“降级”。因此,它将抛出编译错误


    我希望这有助于你理解发生了什么。

    有趣的问题。你可能会找到你问题的答案。你似乎把
    double
    float
    搞混了。JLS 8的第5.1.2节将
    float
    调用为
    double
    19个“加宽原语转换”中的一个。您的回答意味着
    double
    可以扩展为
    float
    public static int sum(int ...a) {
        return 0;
    }
    
    public static boolean sum(boolean ...a) {
        return true;
    }