public class Main {
static void over_Var(float a, Character... ab) {
System.out.println("Method1");
}
static void over_Var(Character... ab) {
System.out.println("Method2");
}
public static void main(String[] args) {
System.out.println("Hello World");
over_Var(1, 'm');
over_Var('k', 'm');
}
}
I'm getting error as this:
Main.java:19: error: reference to over_Var is ambiguous
over_Var('k', 'm');
^
both method over_Var(float, Character...) in Main and method over_Var(Character...) in Main
match 1 error
The code works fine if I use char
instead of Character
, or remove the line over_Var('k', 'm');
Why am I getting error like this?
Ambiguous Invocation. □ Sometimes there may be two or more possible. matches for an invocation of a method, but the. compiler cannot determine the most specific match. This is referred to as ambiguous invocation.
This ambiguous method call error always comes with method overloading where compiler fails to find out which of the overloaded method should be used. Suppose we have a java program like below.
If the grammar has ambiguity then it is not good for a compiler construction. No method can automatically detect and remove the ambiguity but you can remove ambiguity by re-writing the whole grammar without ambiguity.
Ambiguity errors occur when erasure causes two seemingly distinct generic declarations to resolve to the same erased type, causing a conflict.
over_Var(1, 'm');
is not ambiguous1
is an integer. It can't be passed to a parameter of type Character
or char
directly (without casts), so the only option is the (float, Character...)
overload. There does exist an int
to float
widening primitive conversion, which is permitted in an invocation context.
You might have thought that 1
could be converted to a Character
because you can do that in assignment contexts.
Character a = 1;
However, this is purely because in the "Assignment Contexts" section of the JLS (see above link), there is this part that begins:
In addition, if the expression is a constant expression (§15.28) of type
byte
,short
,char
, orint
:[...]
The section for invocation contexts does not have this paragraph. So in reality, assignment contexts give constant expressions (like 1
) special treatment, allowing them to be converted to smaller types than they actually are. Invocation contexts do not do this.
over_Var('k', 'm');
is ambiguousIn this case, both overloads are applicable. 'k'
is a char
, and the conversion from char
to float
(widening primitive conversion again) is allowed in an invocation context. The conversion from char
to Character
is also allowed in a loose invocation context.
If there are multiple applicable methods, the compiler chooses the most specific one. Which is more specific? Well, the second parameter of both calls would be Character
, so we just need to consider the first parameter's type. One's float
and the other's Character
. Which one of these is more specific depends on their subtyping relationship. According to the subtyping rules, they are unrelated, so neither is more specific, and so you get a compiler error.
This is a simplification of the entire section of 15.12.2 of the spec, which I strongly encourage you to explore yourself :)
char
worksUnlike float
and Character
, float
and char
actually are related! Specifically:
double
is a super type offloat
float
is a super type oflong
long
is a super type ofint
int
is a super type ofchar
int
is a super type ofshort
short
is a super type ofbyte
So char
is a subtype of float
, so over_Var(char...)
is more specific than over_Var(float, char...)
, and hence will be preferred.
To call (float, Character...)
, you can just cast:
over_Var((float) 'k', 'm');
To call (Character...)
, you can pass in a Character[]
.
over_Var(new Character[] {'k', 'm'});
The problem here is not that you have variable length arguments. This is a The method X is ambiguous for the type Y
error, explained in the link:
If more than one member method is both accessible and applicable to a method invocation … The Java programming language uses the rule that the most specific method is chosen.
java compiler doesn’t consider any of them to be more specific, hence the method ambiguous call error
First of all... why the connection between chars and floats?
That has to do with how chars work under the hood in Java.
Example:
System.out.println(200 - 'a'); // subtracting a char from 200
System.out.println(0 - 'a'); // subtracting a char from 0
Should Return:
103
-97
So what's the solution? You indicated one: change Character
to char
. But why does that work? You have stumbled upon very interesting Java behavior. Take this code for example:
public class Main {
static void over_Var(float a, Character b) {
System.out.println("Method1");
}
static void over_Var(char a, Character b) {
System.out.println("Method2");
}
static void over_Var(Character a, Character b) {
System.out.println("Method3");
}
public static void main(String[] args) {
over_Var('k','m');
}
}
This will have an error due to ambiguity between the char
and Character
.
Comment out the first function. It will still have the error due to ambiguity between char
and Character
Comment out the second function. It will fail due to ambiguity between float
casted as Character
, and Character
Comment out the third function. It will print Method2
. It knows to prioritize char
over float
!
This appears... to violate transitivity. char + Character = ambiguity. Character + float = ambiguity. But char + float = non-ambiguous? I will leave you with the word "strange".
Edit: the reason for this (see Sweeper's better answer), is that it knows to prioritize char
over float
because they are related types; char is a subtype of float. On the other hand, Character is not related. (In other words, the reason for the apparent lack of "transitivity" is that specificity can only be assessed in the context of the types being compared.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With