6
public class Test
{
    public static void printValue(int i, int j, int k)
    {
        System.out.println("int");
    }

    public static void printValue(byte...b)
    {
        System.out.println("long");
    }

    public static void main(String... args)
    {
        byte b = 9;
        printValue(b,b,b);
    }
}

The output of the above code is "int". But it should be "long" because byte type argument function is already present. But here the program is promoting the byte values to int, but it should not be the case.

Please can someone clarify what is going on here?

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
  • 2
    Please read the documentation on including code in a post, and use the preview to check that it looks reasonable before you post. – Jon Skeet Jun 01 '15 at 12:33

2 Answers2

12

JLS 15.12.2 is the relevant bit of the spec to look at here. In particular - emphasis mine:

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.

    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.

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

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

In your case, the first phase finds a match without using variable arity method invocation or boxing, hence that's the result. As noted in the spec, this is basically for backward compatibility.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you very much Jon. It clarifies my doubt. But, I could not get the third phase. – Shipra Varshney Jun 01 '15 at 12:43
  • 1
    @ShipraVarshney You could take a look at my answer for a simpler understanding. – Chetan Kinger Jun 01 '15 at 12:44
  • @ShipraVarshney: Basically it's "Try to find a match without using boxing or varargs. Then try to find a match using boxing, but not varargs. Then try to find a match using boxing and varargs." – Jon Skeet Jun 01 '15 at 12:50
4

Variable argument methods will always be the last one to be chosen by the compiler in case of overloaded methods. Promotion of a byte to an int (widening-conversion) will be preferred over the method that takes a var-arg parameter.

The reason behind this is that the language needs to be backward compatible. Older features will take priority over newer features. A simple way of understanding what the JLS says about variable arguments is that widening will beat boxing and boxing will beat var-args.

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82