Varargs Java模糊调用

kar*_*rim 68 java methods overloading variadic-functions

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

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

public static double sum(double ...a) {
    return 0.0;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

public static boolean sum(boolean ...a) {
    return true;
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*nik 56

这里适用的一般规则是:如果一个方法签名严格比另一个更具体,那么Java选择它而没有错误.

当然,如果您可以完全删除方法签名,则方法签名更具体,而另一个不太具体的方法签名将适用于每个现有调用.

当与签名之间的选择呈现sum(int... args)sum(double... args),签名sum(int... args)是更具体的,因为该方法的任何调用也可以上通过sum(double... args)运用一种扩大转换.对于sum(boolean... args)无法进行类似转换的方法,情况也是如此.

Java语言规范,SE 8版本:

15.12.方法调用表达式

15.12.2.5.选择最具体的方法

Java编程语言使用选择最具体方法的规则.

...

对于具有参数表达式e1,...,ek的调用,如果满足以下任何条件,则一个适用的方法m1比另一个适用的方法m2更具体:

...

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

...

如果S <:T(§4.10),则类型S对于任何表达式比类型T更具体.


4.10.分型

4.10.1.原始类型之间的子类型

double> 1 float

漂浮> 1长

长> 1 int


hmc*_*ake 7

本回答所述,在选择要使用的重载方法时遵循规则.

报价:

  1. 原始扩展使用可能的最小方法参数
  2. 包装类型不能扩展到另一种包装类型
  3. 您可以从int到Integer并将其扩展为Object但不包含Long
  4. 加宽节拍拳击,拳击节拍Var-args.
  5. 你可以Box然后加宽(一个int可以通过整数成为对象)
  6. 你不能加宽然后Box(一个int不能变长)
  7. 不能合并VAR-ARGS,有两个加宽拳击.

(让我们像这样重新定义规则1:"原始扩展使用尽可能最具体的方法参数.")

因此,考虑到这些规则,我们可以了解这里发生了什么:

根据规则一,原始扩展使用尽可能最具体的方法参数.由于a int由非十进制数表示(例如1),a double由十进制数表示,精度比a float(例如1.0)的精度高32个字节,我们可以说ints是"小于"或"小于" doubles,按照这种逻辑,ints可以"升级"为doubles,doubles可以"降级"为ints.

简而言之,可以扩展到另一个原语(例如int- > float- > double)的原语比另一个原语更具体.例如,一个int更具体的double,因为1可以提升1.0.

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

那么,当你介绍分别采用ints和booleans(相互之间不能加宽的类型)的相同方法时,编译器现在无法选择使用的方法,因为ints不能像ints 那样被"提升"或"降级" ,floats和doubles.因此,它会抛出编译错误.

我希望这可以帮助您了解正在发生的事情.