使用 Vararg 重载 Java 方法

Keq*_* Li 5 java

我有两个版本addValues,一个带有可变参数。

double addValues(double ... values) {
    double result = 0d;
    for (double value : values)
        result += value;
    return result;
}

double addValues(double v1, double v2) {
    return v1 + v2;
}
Run Code Online (Sandbox Code Playgroud)

当我调用addValues(2, 3)which 对我来说看起来不明确时,为什么 Java 选择addValues(double v1, double v2)版本来运行代码?Java 如何确定哪个版本“更接近”调用?

谢谢。

Pau*_*ton 8

这个答案给出了 Java 语言规范的相关部分。但是它太复杂了,需要几个例子来解释。

如果可能,编译器将始终选择不需要“可变参数调用”或自动装箱或自动拆箱的方法。变量参数调用是指通过传递最后一个参数(而不是数组)的参数列表来调用可变参数方法。

例如,假设您有一个带有签名的方法

void foo(int... arr)
Run Code Online (Sandbox Code Playgroud)

这是一个可变的参数调用......

foo(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

……但这不是。

foo(new int[] {1, 2, 3});
Run Code Online (Sandbox Code Playgroud)

因此,在您的情况下,请addValues(2, 3)使用第二个版本,因为这不是可变参数调用。

说编译器总是偏爱不涉及可变参数的方法而不是涉及可变参数的方法是不正确的,如下例所示:

public static void bar(int... a) {
    System.out.println("Varargs");
}

public static void bar(Object a) {
    System.out.println("Object");
}

public static void main(String[] args) {
    bar(new int[] {1, 2, 3});    // Prints Varargs
} 
Run Code Online (Sandbox Code Playgroud)

在这个例子中,这两个选择都不是变量参数调用,但是第一个版本被调用,因为它更具体。

这些规则使更改非可变参数签名成为可能

baz(int[] arr)
Run Code Online (Sandbox Code Playgroud)

到一个可变参数

baz(int... arr)
Run Code Online (Sandbox Code Playgroud)

不改变任何现有程序的行为。