Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Method Overloading with Vararg

Tags:

java

I've two versions of addValues, one with vararg parameters.

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

double addValues(double v1, double v2) {
    return v1 + v2;
}

When I call addValues(2, 3) which looks ambiguous to me, why Java selects the addValues(double v1, double v2) version to run the code? How does Java determine which version is 'closer' to the invocation?

Thanks.

like image 359
lkq Avatar asked Mar 29 '16 21:03

lkq


2 Answers

This answer gives the relevant section of the Java Language Specification. However it is so complicated that it requires a few examples to explain.

The compiler will always choose a method not needing "variable arity invocation" or auto boxing or auto unboxing if possible. Variable arity invocation is when you invoke a varargs method by passing a parameter list for the last argument (rather than an array).

For example, suppose you have a method with signature

void foo(int... arr)

This is a variable arity invocation...

foo(1, 2, 3);

...but this is not.

foo(new int[] {1, 2, 3});

So in your case, addValues(2, 3) uses the second version as this is not a variable arity invocation.

It is not true to say that the compiler will always favour a method not involving varargs over one that does involve varargs, as this example shows:

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
} 

In this example, neither choice is a variable arity invocation, but the first version is invoked as it is more specific.

These rules made it possible to change a non-varargs signature

baz(int[] arr)

to a varargs one

baz(int... arr)

without changing the behaviour of any existing program.

like image 144
Paul Boddington Avatar answered Sep 27 '22 22:09

Paul Boddington


The compiler will usually favor a non-varargs overload over a varargs overload. When varargs was added in Java 5, they wanted to add varargs overloads while still remaining backwards compatible, meaning that prior code that was necessarily calling a non-varargs overload would still call that overload and not the varargs overload.

This is explained in the JLS, Section 15.12.2:

The remainder of the process is split into three phases, to ensure compatibility with versions of the Java programming language prior to Java SE 5.0. The phases are:

  1. The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null)), as m(Object[]) is more specific.

  1. The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.

This ensures that a method is never chosen through variable arity method invocation if it is applicable through fixed arity method invocation.

  1. The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

(bold emphasis mine)

like image 38
rgettman Avatar answered Sep 27 '22 22:09

rgettman