I want to create two functions, say
long min(long...);
int min(int...);
But when I try to invoke the second i.e min(1, 5)
one I get ambiguous method call
Is there workaround except renaming?
I want to create two functions, say
long min(long...);
int min(int...);
But when I try to invoke the second i.e min(1, 5)
one I get ambiguous method call
Is there workaround except renaming?
It is a known bug
The behaviour you describe is a bug which has been fixed with Java 7. See details in the release notes, section called "Changes in Most Specific Varargs Method Selection".
The reason why it should compile
Variable arity comes last in determining the most specific method. The rules to determine which vararg method applies when there are several are defined in JLS 15.12.2.4 - here is an extract:
One variable arity member method named m is more specific than another variable arity member method of the same name if either:
- [...]
- One member method has k parameters and the other has n parameters, where n ≥ k, and:
- The types of the parameters of the first method are U1, ..., Uk-1, Uk[].
- The types of the parameters of the other method are T1, ..., Tn-1, Tn[].
- For all j from 1 to n, Uj <: Tj
In your case, k = n, and U1[] = int[]
and T1[] = long[]
so the determination can be made if int <: long
or the opposite.
In other words, the type taken into account is not int[]
vs. long[]
but int
vs long
. And it happens that int <: long
so the int...
method should be chosen and it should compile.
Conclusion:
The code should (and does) compile fine with Java 7 but would not compile with Java 5 or 6. The code below prints int
with Java 7:
public class Test1 {
public static void main(String[] args) {
new Test1().m(1, 2);
}
int m(int... i) {
System.out.println("int");
return 0;
}
long m(long... i) {
System.out.println("long");
return 0;
}
}
The problem is when you invoke those method with an integer
, none of the methods provide exact match for the argument, as you used var-args
. Also, both the var-args
can take int
values separated by commas as argument. Hence the ambiguous method
error.
When you call overloaded method, Compiler
chooses the exact match
first. Then the nearest type
to cast.
Now, since var-args
is just an array
, compiler cannot decide which array to use while passing an integer
value. As, neither arrays can be considered as exact match
or nearest conversion
. So, it takes both the method eligible for call.
There are lot more rules regarding the method invocation
in case of Overloading
. You can learn those from the Java Language Specification
.
As in @assylias answer this problem has been fixed in Java 7. But it will not work in Java version < 7.
Try this
public class Test {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new Test().m(100L,512L);
new Test().m(100,512);
}
int m(int... i) {
System.out.println("int");
return 0;
}
long m(long... i) {
System.out.println("long");
return 0;
}
}
Those method signatures are unique, and are valid method overloads.
The problem must be in the method call argument. My guess is that you are calling the method with a literal, like:
min(100)
And it doesnt like that because 100 is an integer literal, but it gets automatically converted to a long.
disambiguating the method calls by using L at the end of long literals should fix the problem:
min(100L)
Also, you could make the calls explicit by using the Java Object Integer and Long, and let autoboxing take care of the conversion to primitive types:
min(new Long(100))
min(new Integer(100))