13

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.

Community
  • 1
  • 1
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • I think that the var-args is transformed in an array. So, for me the second line is logical. I mean, an Object[] is supposed to be matched first to an Object[] and then to an Object. – Jason May 17 '11 at 15:19
  • @Jason: I agree, but I'm not asking what is logical, I'm asking what the JLS dictates. I'm working on reflective runtime method dispatch to be as compatible as possible with compile-time method dispatch, and in order to do so, I need an explicit standard to follow, not just what I think is the right observed behavior. The "logical" result for all of these is to print 42, because "hi" is `String` and therefore a better match than `Object`. So there are two conflicting measures of "better", and therefore you have to fall back on the normative definitions given by the JLS. – Jason S May 17 '11 at 15:23

2 Answers2

9

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.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151
  • 1
    Ahhhh! (light bulb appears) OK, so a variable arity method can also be considered to be a fixed arity method that is applicable to a compatible array argument. – Jason S May 17 '11 at 15:25
  • It's 8.4.1 -- if you edit to link to http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.1 I'll accept. – Jason S May 17 '11 at 15:27
  • That's how I'm reading it. And then by 15.12.2.5, the compute(Object,Object[]) method is more specific than compute(Object,Object). – Andy Thomas May 17 '11 at 15:29
4

Vararg methods can be called with multiple parameters (a, b, c) or as an array ({a, b, c}). Because you are passing an array that matches the type of the varargs it takes precedence.

Reference: http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.1

JustinKSU
  • 4,875
  • 2
  • 29
  • 51