manvel
manvel

Reputation: 133

Overloading varargs arrays, choosing method

I have a two overloaded methods: foo and bar

//Object[]... vs Integer[]...
public static String foo(Object[]... args)  { return "Object[] args"; }
public static String foo(Integer[]... args) { return "Integer[] args";}

//Object... vs Integer[]...
public static String bar(Object... args) {return "Object args";}
public static String bar(Integer[]... args) {return "Integer[] args";}

Now when I use them like:

Integer[] i = { 5 };
System.out.println(foo(i));//Object[]... vs Integer[]...
System.out.println(bar(i));//Object... vs Integer[]...

I am getting

Integer[] args
Object args

Here is the question: why do we have 2 different outputs?
Integer[] can be implicitly cast to both Object, and Object[].

Upvotes: 13

Views: 511

Answers (2)

Pavitra Kansara
Pavitra Kansara

Reputation: 828

This is basically compiler deciding to call the most specific method among all.

When you call

System.out.println(foo(i));//Object[]... vs Integer[]...

it will call the foo(Integer[]... args)

Because at run time the JVM delegates the call to the method with Integer[][] argument and not method with Object[][] param as specified by varags. As it will be more specific to call method with Integer[][] rather than Object[][].


In the later statement, when you call

System.out.println(bar(i));//Object... vs Integer[]...

it will go to the bar(Object... args)

Again by using varags, the type of param will be Object[] and not Object[][]. Again the compiler will call the most specific method which will be the one having Object... args.

If you change the method signature by removing varags as per following:

   //Object... vs Integer[]...
    public static String bar(Object args) {

        return "Object args";
    }

    public static String bar(Integer[] args) {
        return "Integer[] args";
    }

then you will notice that it will call the bar(Integer[] args) as it is more specific to the method call.

So to be more precise as per JLS Subtyping among Array Types,

  • If S and T are both reference types, then S[] > T[] iff S > T.
  • Object > Object[]

This means that a call of Integer[] will be made to method having Integer[][] and not Object[][]. Where as a call of Integer[] will be made to Object[] rather than Integer[][].

See here for choosing the most specific method.

Upvotes: 4

Matt Timmermans
Matt Timmermans

Reputation: 59263

In the first case, the type of args is actually Integer[][], i.e., your array was boxed up into another array by varargs. The compiler chooses the Integer[] version because it is the most specific type.

In the second case, args == i and is an Integer[]. In this case, the compiler had to choose between wrapping it up in a new array to call the Integer[]... version or just casting your Integer[] to an Object[]. It chose the second one because that's the rule.

The moral of the story is: don't overload varargs methods -- it's confusing.

Upvotes: 3

Related Questions