overloading method priority in java

It is now clear that the method var(int...) is selected and not var(Integer...).

The reason is that only certain conversions are allowed to be applied, and it can only be one of these conversions from the list, not a chain of conversions.
The java compiler is not allowed to do a widening primitive conversion first, and then a boxing conversion.

It’s specified in the Java Language Specification in section 5.3

5.3. Method Invocation Conversion

Method invocation conversion is applied to each argument value in a
method or constructor invocation (§8.8.7.1, §15.9, §15.12): the type
of the argument expression must be converted to the type of the
corresponding parameter.

Method invocation contexts allow the use of _one of_ the following:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a widening reference conversion (§5.1.5)
  • a boxing conversion (§5.1.7) optionally followed by widening reference
    conversion
  • an unboxing conversion (§5.1.8) optionally followed by a widening
    primitive conversion.

The only option for the compiler is to do:

  1. a widening primitive conversion on the first argument
  2. an unboxing conversion on the second argument

That turns (byte, Integer) into (int, int).

It cannot first turn the first argument byte into an int and then apply a boxing conversion on the same argument from int to Integer because two conversions in sequence are not allowed.

Let’s go back one step to find out how the compiler selects which overloaded method to invoke. That is described in JLS 15.12.2. (15.12.1 describes how to find the class or interface to search, but we already know that we want to invoke a static method in class Main)

The first two phases that a compiler goes through to select the right overloaded methoddo not apply to variable argument (“variable arity”) methods, but the third phase does:

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

Section 15.12.4 is quite complicated, but the rules that apply here are:

  • first apply the rules for non-variable arity arguments (not applicable in your case)
  • each variable argument in the invocation must be convertable by method invocation conversion (the piece that I copied above) to the type of the variable argument declaration

So..

  1. you try to invoke a method named var with (byte, Integer)
  2. the compiler looks at your method var(Integer...)
  3. it asks: can I convert the first argument, a byte, to Integer (the declared type of the argument in the method)
  4. it looks at the rules in JLS 5.3. It can only apply one of the conversions from the list of 5. None of them can convert a byte to an Integer directly – it cannot do two steps.
  5. So the compiler decides that it cannot select var(Integer...)
  6. then it looks at your other method, var(int...)
  7. According to JLS 5.3, it can convert your first argument, the byte to an int using a widening primitive conversion. That’s a check mark.
  8. Moving on to the second argument, your Integer, it sees that JLS 5.3 allows the compiler to convert it to an int using an unboxing conversion. So that’s also a check mark.
  9. That was the last argument, so var(int...) is a good match.
  10. The compiler now moves on to see if there are more methods that match your invocation. If there are more that do, that will result in an ambiguous-invocation error.
  11. But there are no more methods with the name var, so var(int...) is the only applicable method. The compiler will now generate code to do the necessary conversions and invoke that method.

Leave a Comment