Question

I think this would be a stupid question a little bit, but I can not sure why it is.

code;

public class OverloadingTest {
    public static int sum(int ...a){
        int sum=0;
        for(int i : a){
            sum += i;
        }
        System.out.print("this is variant args//");
        return sum;
    }

    public static double sum(double a, double b) {
        return a + b;
    }

    public static void main(String[] args) {
        System.out.println(sum(1.5, 2.5));
        System.out.println(sum(10, 20));
        System.out.println(sum(10, 20,30));
    }
}

results I expected;

4.0
this is variant args//30
this is variant args//60

actual results in console:

4.0
30.0
this is variant args//60

I can not sure why results of sum(10, 20) 30.0, not 30 of variable argument.

Was it helpful?

Solution

This is because the compiler always makes the choice to use the most specific method.

Since your second invocation has two arguments, and an int can be converted to a double without loss of precision (see JLS, section 5.1.2), the compiler elects to call your two-argument method.

An IDE will warn you here about the implicit int to double conversion.


edit: as @OlegEterkhin mentions in comments, see JLS, section 15.2.2 for the process used by the compiler to select which method will be used.

And no, this won't work:

int x = sum(10, 20);

OTHER TIPS

The answer is in JLS section 15.12.2. Basically, the compiler tries to find any applicable method without having to expand varargs, only using varargs if it has to:

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:

  • 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. [...]

  • 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. [...]

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

In this case, the first phase does find a match, as sum(double, double) is applicable for the call sum(10, 20) due to the implicit conversion from int to double.

In the line:

System.out.println(sum(10, 20));

The number of the parameters match the signature of sum(double a, double b) and it's the most accurate method and it's the one chosen by the compiler.

See 15.12.2. Compile-Time Step 2: Determine Method Signature for details.

Based upon this post Varargs in method overloading in Java

There are some rules that are followed when selecting which overloaded method to select, when Boxing, Widening, and Var-args are combined: -

Primitive widening uses the smallest method argument possible
Wrapper type cannot be widened to another Wrapper type
You can Box from int to Integer and widen to Object but no to Long
Widening beats Boxing, Boxing beats Var-args.
You can Box and then Widen (An int can become Object via Integer)
You cannot Widen and then Box (An int cannot become Long)
You cannot combine var-args, with either widening or boxing

Type inference has a sort of priority over the varargs. Since you call a method with 2 arguments, it tries to find a match with 2 arguments (even with type inference) before searching for varargs methods (even with the right type).

This behavior is defined in the specification. "Variable arity methods, boxing, and unboxing " are handled in the third phase of method signature resolution, after first trying to match the signature without using variable arity methods.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top