Method Overloading and Ambiguity in Varargs in Java

Prerequisite – Varargs , Method Overloading

Method Overloading in Varargs

Overloading allows different methods to have same name, but different signatures where signature can differ by number of input parameters or type of input parameters or both. We can overload a method that takes a variable-length argument by following ways:

  • Case 1 – Methods with only Varargs parameters: In this case, Java uses the type difference to determine which overloaded method to call. If one method signature is strictly more specific than the other, then Java chooses it without an error.
    //Java program to illustrate 
    //method overloading in varargs
    public class varargsDemo
    {
        public static void main(String[] args)
        {
            fun();
        }
    
        //varargs method with float datatype
        static void fun(float... x)
        {
            System.out.println("float varargs");
        }
        
        //varargs method with int datatype
        static void fun(int... x)
        {
            System.out.println("int varargs");
        }
        
        //varargs method with double datatype
        static void fun(double... x)
        {
            System.out.println("double varargs");
        }
    }

    Output:

    int varargs
    

    This output is due to the fact that int is more specific than double. As specified in the JLS section 15.12.2.5, If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen according to type promotion. The following rules define the direct supertype relation among the primitive types in this case:

    • double > float
    • float > long
    • long > int
    • int > char
    • int > short
    • short > byte
  • Case 2 – Methods with Varargs alongwith other parameters In this case, Java uses both the number of arguments and the type of the arguments to determine which method to call.

    Below is the java program that overloads fun( ) method three times:

    // Java program to demonstrate Varargs 
    // and overloading.
    class Test 
    {
    	// A method that takes varargs(here integers).
    	static void fun(int ... a) 
    	{
    		System.out.print("fun(int ...): " +
    				"Number of args: " + a.length +
    				" Contents: ");
    		
    		// using for each loop to display contents of a
    		for(int x : a)
    			System.out.print(x + " ");
    		
    		System.out.println();
    	}
    	
    	// A method that takes varargs(here booleans).
    	static void fun(boolean ... a)
    	{
    		System.out.print("fun(boolean ...) " +
    				"Number of args: " + a.length +
    				" Contents: ");
    		
    		// using for each loop to display contents of a
    		for(boolean x : a)
    			System.out.print(x + " ");
    		
    		System.out.println();
    	}
    	
    	// A method takes string as a argument followed by varargs(here integers).
    	static void fun(String msg, int ... a) 
    	{
    		System.out.print("fun(String, int ...): " +
    				msg + a.length +
    				" Contents: ");
    		
    		// using for each loop to display contents of a
    		for(int x : a)
    			System.out.print(x + " ");
    		
    		System.out.println();
    	}
    	
    	public static void main(String args[])
    	{
    		// Calling overloaded fun() with different  parameter
    		fun(1, 2, 3);
    		fun("Testing: ", 10, 20);
    		fun(true, false, false);
    	}
    }
    

    Output:

    fun(int ...): Number of args: 3 Contents: 1 2 3 
    fun(String, int ...): Testing: 2 Contents: 10 20 
    fun(boolean ...) Number of args: 3 Contents: true false false 
    

Varargs and Ambiguity

Sometimes unexpected errors can result when overloading a method that takes a variable length argument. These errors involve ambiguity because both the methods are valid candidates for invocation. The compiler cannot decide onto which method to bind the method call.

// Java program to illustrate Varargs and ambiguity
class Test 
{
	// A method that takes varargs(here integers).
	static void fun(int ... a) 
	{
		System.out.print("fun(int ...): " +
				"Number of args: " + a.length +
				" Contents: ");
		
		// using for each loop to display contents of a
		for(int x : a)
			System.out.print(x + " ");
		
		System.out.println();
	}
	
	// A method that takes varargs(here booleans).
	static void fun(boolean ... a)
	{
		System.out.print("fun(boolean ...) " +
				"Number of args: " + a.length +
				" Contents: ");
		
		// using for each loop to display contents of a
		for(boolean x : a)
			System.out.print(x + " ");
		
		System.out.println();
	}
	
	public static void main(String args[])
	{
		// Calling overloaded fun() with different  parameter
		fun(1, 2, 3); //OK
		fun(true, false, false); //OK
		fun(); // Error: Ambiguous!
	}
}

In above program, the overloading of fun( ) is perfectly correct. However, this program will not compile because of the following call:

fun(); // Error: Ambiguous!

According to (JLS 15.2.2), there are 3 phases used in overload resolution: First phase performs overload resolution without permitting boxing or unboxing conversion, Second phase performs overload resolution while allowing boxing and unboxing and Third phase allows overloading to be combined with variable arity methods, boxing, and unboxing. If no applicable method is found during these phases, then ambiguity occurs.
The call above could be translated into a call to fun(int …) or fun(boolean …). Both are equally valid and do not be resolved after all three phases of overload resolution because both the data types are different. Thus, the call is inherently ambiguous.

Another example of ambiguity:
The following overloaded versions of fun( )are inherently ambiguous:

static void fun(int ... a) { // method body  }
static void fun(int n, int ... a) { //method body }

Here, although the parameter lists of fun( ) differ, there is no way for the compiler to resolve the following call:

fun(1)

This call may resolve to fun(int … a) or fun(int n, int … a) method, thus creating ambiguity. To solve these ambiguity errors like above, we will need to forego overloading and simply use two different method names.

This article is contributed by Gaurav Miglani. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

GATE CS Corner    Company Wise Coding Practice





Writing code in comment? Please use ide.geeksforgeeks.org, generate link and share the link here.