Search code examples
javavariadic-functionsjls

Java: overloaded method resolution and varargs -- confusing example


Just when I thought I understood JLS15.12 as it applied to varargs, here's this example:

package com.example.test.reflect;

public class MethodResolutionTest2 {
    public int compute(Object obj1, Object obj2) {
        return 42;
    }   
    public int compute(String s, Object... objects)
    {
        return 43;
    }

    public static void main(String[] args) {
        MethodResolutionTest2 mrt2 = new MethodResolutionTest2();
        System.out.println(mrt2.compute("hi",  mrt2));  
        System.out.println(mrt2.compute("hi",  new Object[]{mrt2}));    
        System.out.println(mrt2.compute("hi",  new Object[]{mrt2, mrt2, mrt2}));
    }
}

which prints out

42
43
43

I understand the first line: JLS15.12 says method resolution happens in phases, and phases 1 and 2 ignore varargs methods to find out if there's a compatible method, with phase 3 (include varargs) happening only if phases 1 and 2 fail. (See the JLS and this SO question.) So compute(String s, Object... objects) always gets ignored if compute(Object obj1, Object obj2) applies.

But I don't understand why 43 is printed for the other two lines. An Object[] is also an instance of an Object, so why does it match the varargs method?


edit:

...and this

Object arg2 = new Object[]{mrt2};
System.out.println(mrt2.compute("hi", arg2));   

prints 42.


Solution

  • In section 8.4.1:

    If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[].

    Since you're explicitly providing an array, this allows the second two calls to match the variable arity method in the first phase, without consideration of variable arity.