Overloaded methods for java certification exam

Viewed 202

I am preparing for Java certification exam and one thing that I do not understand is below:

class Calculator {
    public static long add(int a, long... b) {
        System.out.println("int a, Var args long b");
        int total = a;
        for (long val : b) {
            total += val;
        }
        return total;
    }
    public static long add(int a, Long b) {
        System.out.println("int + Long");
        return a + b;
    }
}
public class OverloadTests {
    public static void main(String[] args) {
        var result = Calculator.add(1, 2);
        System.out.println("result = " + result);
    }
}

Java documentation (https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2) says that:

1- The first phase 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

2- The second phase 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.

3- The third phase allows overloading to be combined with variable arity methods, boxing, and unboxing.

So, with these rules, I think this should happen:

  • Calculator.add(1, 2); looks for (int, int) signature, but fails to find. It also looks for (int, long), (int, float), and (int, double) with this order. Since we are in step 1, we are not looking varargs, we shouldn't have a match.
  • In this step, it performs boxing/unboxing. As we do have (int, Long), I expected the result to be "int + Long".
  • In this step, it also looks for varargs, and if the previous step was not there, it should have found the "int a, Var args long b".

What am I missing in here? I was expecting the result to be "int + Long", but it is "int a, Var args long b"

EDIT: The code is taken from Udemy Course named Java SE 11 Developer 1Z0-819 OCP Course - Part 1 from the Author Tim Buchalka

2 Answers

If you remove the method add(int a, long... b) you will find that your code won't compile because the remaining method add(int a, Long b) cannot be called with add(1, 2) because 2 is an int and a primitive int cannot be boxed into a Long. Likewise, the statement Long a = 2; is invalid. Therefore the only matching candidate is add(int a, long... b).

The rules for overload applicability are rooted in the rules for conversion (JLS Ch5, "Conversions and Contexts".) There are different conversions defined (primitive widening (int to long), boxing (int to Integer), reference widening (String to Object), etc).

In any given situation, any given conversion may or may not apply, depending on the context. Contexts include assignment context, method invocation context, cast context, etc, The difference between the first phase of overload resolution and the later phases is the difference between strict invocation context and loose invocation context.

What is hanging you up is probably that add(int, Long) is not applicable to (int, int) even in loose invocation context. This is because (JLS 5.3) a widening primitive conversion followed by a boxing conversion is not one of the permitted conversions in an invocation context. If you called add(0, 0L) it would be applicable (boxing conversion).

The varargs case is applicable in a loose context because there is a widening primitive conversion from int to long.

Related