Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method overloading with variable arguments (varargs) [duplicate]

I am surprised by seeing the output of this code :

public class File
{
    public static void main(String[] args)
    {
        movie();
    }

    static void movie(double... x)
    {
        System.out.println("No varargs");
    }

    static void movie(int... x)
    {
        System.out.println("One argument");
    }
}

It outputs,

One argument

Why is it so ?

I thought that this code would not compile because the call to movie() is ambiguous, but it runs fine and outputs One argument.

If I modify the code to:

public class File
{
    public static void main(String[] args)
    {
        movie();
    }

    static void movie(boolean... x)  //Changed the parameter type to boolean from double
    {
        System.out.println("No varargs");
    }

    static void movie(int... x)
    {
        System.out.println("One argument");
    }
}

There is an error message.

Why does the first code run fine, but the second gives an error?

like image 381
Frosted Cupcake Avatar asked Aug 30 '15 05:08

Frosted Cupcake


People also ask

How many maximum number of Varargs or variable arguments can be there in a method or constructor in Java?

There can be only one variable argument in a method. Variable argument (Varargs) must be the last argument.

What is the maximum number of Varargs or variable arguments?

Each method can only have one varargs parameter. The varargs argument must be the last parameter.

Can we overload varargs in Java?

Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.

What is the rule for using Varargs?

Rules for varargs:There can be only one variable argument in the method. Variable argument (varargs) must be the last argument.


1 Answers

This behaviour is due to the fact that int is more specific than double while there is no such comparison between int and boolean.

As specified in the JLS section 15.12.2.5 (emphasis mine):

One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:

  • ...
  • m2 is not generic, and m1 and m2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m1 are S1, ..., Sk and the first k variable arity parameter types of m2 are T1, ..., Tk, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ k). Additionally, if m2 has k+1 parameters, then the k+1'th variable arity parameter type of m1 is a subtype of the k+1'th variable arity parameter type of m2.

What more specific actually means is later defined with subtyping:

A type S is more specific than a type T for any expression if S <: T.

This means that S is more specific than T is S is a subtype of T. For primitive types, this comes down to the following properties:

  • double > float
  • float > long
  • long > int
  • int > char
  • int > short
  • short > byte

Notice that boolean is not there.

As such,

public static void main(String[] args) {
    movie();
}

static void movie(int... x) { }
static void movie(short... x) { }
static void movie(double... x) { }
static void movie(byte... x) { }

compiles and movie(byte... x) will be called because it is the most specific.

However,

public static void main(String[] args) {
    movie();
}

static void movie(int... x) { }
static void movie(boolean... x) { }

does not compile because boolean cannot be compared to int.

like image 67
Tunaki Avatar answered Oct 24 '22 23:10

Tunaki