Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java overloading with variable length arguments

Why there is no compile error in this code:

public class OverloadingVarArgs
{
    public void fun1(int... b)
    {
        System.out.println("int");
    }
    public void fun1(long... a)
    {
        System.out.println("long");
    }
    public static void main(String[] args)
    {
        OverloadingVarArgs obj = new OverloadingVarArgs();
        obj.fun1();
    }

}

But this code gives compile error!

public class OverloadingVarArgs
{
    public void fun1(int... b)
    {
        System.out.println("int");
    }
    public void fun1(boolean... a)
    {
        System.out.println("boolean");
    }
    public static void main(String[] args)
    {
        OverloadingVarArgs obj = new OverloadingVarArgs();
        obj.fun1();
    }
}

I believe there should be compile error in both the case, but this is not so.

like image 712
user3768478 Avatar asked Dec 15 '14 11:12

user3768478


People also ask

How do you use variable length arguments in Java?

A method with variable length arguments(Varargs) in Java can have zero or multiple arguments. Variable length arguments are most useful when the number of arguments to be passed to the method is not known beforehand. They also reduce the code as overloaded methods are not required.

Can a Varargs method be overloaded?

A method with variable length arguments(Varargs) can have zero or multiple arguments. Also, Varargs methods can be overloaded if required.

How do we implement variable sized arguments in generic programming?

Use int parameter and va_start macro to initialize the va_list variable to an argument list. The macro va_start is defined in stdarg. h header file. Use va_arg macro and va_list variable to access each item in argument list.

How do you overcome ambiguity in Java?

The inclusion of generics gives rise to a new type of error that you must guard against ambiguity. Ambiguity errors occur when erasure causes two seemingly distinct generic declarations to resolve to the same erased type, causing a conflict. Here is an example that involves method overloading.


1 Answers

The rules for selecting the correct overloaded method are as follows:

  • Primitive widening uses the smallest method argument possible
  • Wrapper type cannot be widened to another Wrapper type
  • You can Box from int to Integer and widen to Object but no to Long
  • Widening beats Boxing, Boxing beats Var-args.
  • You can Box and then Widen (An int can become Object via Integer)
  • You cannot Widen and then Box (An int cannot become Long)
  • You cannot combine var-args, with either widening or boxing

Have a look at that last rule. You can not combine widening or boxing with variable length arguments. That means that the types can not be manipulated in any way and you have to perform the comparison as is. int and long can be compared, no problem and the compiler can deduce that int is the smaller of the two. As per the first rule, it will go for the smallest method argument possible, hence it has worked out the correct (and only) route to a method.

However, when you get to boolean and int, there exists no comparison method between the two because of Java's strong typing. With no knowledge of which type is smallest, the compiler has absolutely no clue which method you mean.

More Visual Example

Let's take it step by step from the perspective of the compiler. First, with int and long.

int and long

Step 1 - Checking if the parameters match any arguments and if so, which one it matches exactly

Well, varargs means that you can pass 0 to many arguments. In this case, you've elected to pass 0 arguments, hence your call matches both the int type and the long type.

Step 2 - Attempt to autobox or widen. This should help it work out which one to go for

You're using varargs, so the compiler knows it can't do this, as per the final rule.

Step 3 - Attempt to work out which type is smallest

The compiler is able to compare the type int with the type long. From this, it works out that the int is the smallest type.

Step 4 - Make the call

With the knowledge that int is the smallest type, it then passes the value to the method for execution.

Okay, and now let's do the same thing with boolean and int.

boolean and int

Step 1 - Checking if the parameters match any arguments and if so, which one it matches exactly

Same story. You've passed nothing so match both arguments.

Step 2 - Attempt to autobox or widen. This should help it work out which one to go for

As above, you're not permitted to do this because you used varargs.

Step 3 - Attempt to work out which type is smallest

This is the crucial difference. Here, the types are not comparable. This means that the compiler doesn't know which method you want to call by your parameters or by the smallest type. Ergo, it has been unable to work out the correct route.

Step 4 - Make the call

Without the knowledge of which method to call, it can not continue execution and throws the appropriate exception.

like image 82
christopher Avatar answered Oct 05 '22 23:10

christopher