The following code doesn't compile.
package varargspkg;
public class Main {
public static void test(int... i) {
for (int t = 0; t < i.length; t++) {
System.out.println(i[t]);
}
System.out.println("int");
}
public static void test(float... f) {
for (int t = 0; t < f.length; t++) {
System.out.println(f[t]);
}
System.out.println("float");
}
public static void main(String[] args) {
test(1, 2); //Compilation error here quoted as follows.
}
}
A compile-time error is issued.
reference to test is ambiguous, both method test(int...) in varargspkg.Main and method test(float...) in varargspkg.Main match
It seems to be obvious because the parameter values in the method call test(1, 2);
can be promoted to int
as well as float
If anyone or both of the parameters are suffixed by F
or f
, it compiles.
If we however, represent the receiving parameters in the method signature with respective wrapper types as follows
public static void test(Integer... i) {
System.out.println("Integer" + Arrays.asList(i));
}
public static void test(Float... f) {
System.out.println("Float" + Arrays.asList(f));
}
then the call to the method test(1, 2);
doesn't issue any compilation error. The method to be invoked in this case is the one that accepts one Integer
varargs parameter (the first one in the preceding snippet).
Why is in this case the error as in the first case not reported? It appears that auto-boxing and automatic type promotion are both applied here. Is auto-boxing applied first so that the error is resolved?
The Oracle docs says,
Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.
The last sentence in this link. It's however for the sake of better understanding varargs.
Also to add below code compiles just fine.
public class OverLoading {
public static void main(String[] args) {
load(1);
}
public static void load(int i) {
System.out.println("int");
}
public static void load(float i) {
System.out.println("float");
}
}
EDIT:
The following is the snap shot that indicates the compilation error. I have created a new application therefore the package name is different.
I'm using JDK 6.
In Java 6, the problem lies at the time of
instantiation
of your generics before finding which method is available to call.Same with other two option i.e.
On the other hand, when you use
int
orfloat
, there is no variable type instantiation. When you use1
, it tries to find method withint
as argument first, if not, it promotes the type and identifies the method with float. If both methods available, one with theint
will be used first.Ambiguity issue will not come in Java 7 as it has better handling of data type check and promotion.
You can either
Widen
orBox
but you cannot do both, unless you areboxing and widening
toObject
(An int to Integer(Boxing) and then Integer to Object(Widening) is legal, since every class is a subclass ofObject
, so it is possible forInteger
to be passed toObject
parameter)Similarly an
int
toNumber
is also legal (int -> Integer -> Number) Since Number is the super class ofInteger
it is possible.Let's see this in your example: -
There are some rules that are followed when selecting which overloaded method to select, when Boxing, Widening, and Var-args are combined: -
smallest
method argument possibleint
can becomeObject
viaInteger
)int
cannot becomeLong
)So, based on the above given rules: -
When you pass two integers to above functions,
Widened
and thenBoxed
to fit into aLong
, which is illegal according to rule 5 (You cannot Widen and then Box).Integer
var-args.But in first case, where you have methods with
var-args
of primitive types: -Then
test(1, 2)
can invoke both the methods (Since neither of them is more suitable forrule 1
to apply) : -var-args
Now, when you have methods with exactly one int and one flost: -
Then on invoking using
test(1)
, rule 1 is followed, and smallest possible widening (i.e. theint
where no widening is needed at all) is chosen. So 1st method will be invoked.For more information, you can refer to
JLS - Method Invocation Conversion
Just an opinion - in case of varargs the JVM actually has to create an array of arguments. In case of Integer and Float, it's obvious what type of array it should create. So, it probably might be the reason for no ambiguity error.
But still, it's kind of confusing, why it can't create an array of Integers, when by default 1, 3 are ints.
Looks like this has been discussed here in SO in the past bug with varargs and overloading? and is infact a bug, according to the discussion.
In Java,
1
is how you represent anint
. It can be either auto-boxed to an instance ofInteger
or promoted tofloat
, and this explains why the compiler can't decide on the method it should call. But it will never be auto-boxed toLong
orFloat
(or any other type).On the other hand, if you write
1F
, it is the representation of afloat
, that can be auto-boxed to aFloat
(and, in the same spirit, will never be auto-boxed to anInteger
or anything else).