The ambiguities are those issues that are not defined clearly in the Java language specification. The different results produced by different compilers on several example programs support our observations. Here we will be discussing in the following order.
- Ambiguity method in method overloading
- Methods with only Varargs parameters
- Methods with Varargs along with other parameters
- Ambiguity in multiple inheritances
Type 1: Ambiguity method in method overloading
When you overload methods, you risk creating an ambiguous situation of which one is in which the compiler cannot determine which method to use. For example, consider the following overloaded computeBalance() method declarations:
public static void computeBalance(double deposit)
public static void computeBalance(double withdrawal)
If you declare a double variable named myDeposit and make a method call such as computeBalance(myDeposit);, you will have created an ambiguous situation. Both methods are exact matches for your call. You might argue that a call using a variable named myDeposit “seems” like it should go to the version of the method with the parameter named deposit, but Java makes no assumptions based on variable names. Each version of computeBalance() could accept a double, and Java does not presume which one you intend to use.
Ambiguity Errors
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.
Now we are good to go with type 1 as shown above to describe that is. method overloading in varargs
Overloading allows different methods to have the same name, but different signatures where the signature can differ by the 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.
Example
Java
public class GFG {
static void fun( float ... x)
{
System.out.println( "float varargs" );
}
static void fun( int ... x)
{
System.out.println( "int varargs" );
}
static void fun( double ... x)
{
System.out.println( "double varargs" );
}
public static void main(String[] args)
{
fun();
}
}
|
Output Explanation:
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 along with other parameters. In this case, Java uses both the number of arguments and the type of arguments to determine which method to call.
Example 1:
Java
class GFG {
static void fun( int ... a)
{
System.out.print( "fun(int ...): "
+ "Number of args: " + a.length
+ " Contents: " );
for ( int x : a)
System.out.print(x + " " );
System.out.println();
}
static void fun( boolean ... a)
{
System.out.print( "fun(boolean ...) "
+ "Number of args: " + a.length
+ " Contents: " );
for ( boolean x : a)
System.out.print(x + " " );
System.out.println();
}
static void fun(String msg, int ... a)
{
System.out.print( "fun(String, int ...): " + msg
+ a.length + " Contents: " );
for ( int x : a)
System.out.print(x + " " );
System.out.println();
}
public static void main(String args[])
{
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
Here the fun() method is overloaded three times.
Note: 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 on which method to bind the method call.
Example 2:
Java
class GFG {
static void fun( int ... a)
{
System.out.print( "fun(int ...): "
+ "Number of args: " + a.length
+ " Contents: " );
for ( int x : a)
System.out.print(x + " " );
System.out.println();
}
static void fun( boolean ... a)
{
System.out.print( "fun(boolean ...) "
+ "Number of args: " + a.length
+ " Contents: " );
for ( boolean x : a)
System.out.print(x + " " );
System.out.println();
}
public static void main(String args[])
{
fun( 1 , 2 , 3 );
fun( true , false , false );
fun();
}
}
|
Output:
Output explanation: The overloading of the desired method here named ‘fun()‘ is perfectly correct. However, this program will not compile because of the last call made to ‘fun()’ which can also be interpreted in the code.
Type 2: Ambiguity in multiple inheritances. Inheritance is a relation between two classes where one class inherits the properties of the other class. This relation can be defined using the extends keyword as follows:
public class A extends B {}
The class which inherits the properties is known as a subclass or, child class and the class whose properties are inherited is a superclass or, parent class. In inheritance, a copy of superclass members is created in the sub-class object. Therefore, using the sub-class object you can access the members of both classes.
There are various types of inheritance available namely single, multilevel, hierarchical, multiple and, hybrid. In multiple inheritances, one class inherits the properties of multiple classes. In other words, in multiple inheritances, we can have one child class and n number of parent classes. Java does not support multiple inheritances (with classes).
Implementation:
Diamond problem is one of the major ambiguities that arise here in the case of multiple inheritances. For instance, let us assume that Java does support multiple inheritances. Consider the example below with the following assumptions. Here we have an abstract class named ‘Sample‘ with an abstract method as
Example
Java
public class abstract Sample {
public abstract demo();
}
public class Super1 extends Sample {
public void demo()
{
System.out.println( "demo method of super1" );
}
}
public class Super2 extends Sample {
public void demo()
{
System.out.println( "demo method of super2" );
}
}
public class SubClass extends Super1, Super2 {
public static void main(String args[])
{
SubClass obj = new SubClass();
obj.demo();
}
}
|
Output:
Output Explanation: Then, as per the basic rule of inheritance, a copy of both demo() methods should be created in the subclass object which leaves the subclass with two methods with the same prototype (name and arguments). Then, if you call the demo() method using the object of the subclass compiler faces an ambiguous situation not knowing which method to call. This issue is known as the diamond problem in Java.
Last Updated :
10 Sep, 2021
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...