I'm a little confused about Java's varargs methods:
public static int sum(int ...a) {
return 0;
}
public static double sum(double ...a) {
return 0.0;
}
When I tried to invoke sum()
without passing any argument, then the int
version of method was invoked. I don't understand why; normally the compiler must raise an error.
By contrast, the following piece of code generates a compiler error when I try to invoke sum
without any argument:
public static int sum(int ...a) {
return 0;
}
public static boolean sum(boolean ...a) {
return true;
}
The general rule that applies here is this: if one method signature is strictly more specific than the other, then Java chooses it without an error.
Intuituively, a method signature is more specific if you could delete it entirely and the other, less specific one would be applicable to each existing invocation.
When presented with a choice between the signatures
sum(int... args)
andsum(double... args)
, the signaturesum(int... args)
is more specific because any invocation of that method could also be passed on tosum(double... args)
by applying a widening conversion. The same does not hold for asum(boolean... args)
method, which cannot be similarly converted.Java Language Specification, SE 8 version:
As mentioned in this answer, there are rules followed when selecting which overloaded method to use.
To quote:
(Let's redefine rule 1 like so: "Primitive widening uses the most specific method argument as possible.")
So with these rules in mind we can get an idea of what's going on here:
According to rule number one, primitive widening uses the most specific method argument as possible. Since an
int
is representing by a non-decimal number (e.g.1
) and adouble
is represented by a decimal-number with precision 32 bytes more than that of afloat
(e.g.1.0
), we can say thatint
s are "less than" or "smaller than"double
s, and by that logic,int
s can be "promoted" todouble
s anddouble
s can be "demoted" toint
s.Put simply, a primitive that can be widened to another primitive (e.g.
int
->float
->double
) is more specific than another. For example, anint
is more specific than adouble
because1
can be promoted to1.0
.When you passed in no arguments to these overloaded vararg methods of the same name, since the return is effectively the same (0 and 0.0 respectively), the compiler would choose to use the method that takes in a vararg of type
int
since it is more specific.So, then, when you introduced these same methods that take in
int
s andboolean
s (types that cannot be widened to each other) respectively, the compiler now cannot choose a method to use sinceint
s cannot be "promoted" or "demoted" likeint
s,float
s anddouble
s. Therefore, it will throw a compile error.I hope this helps you to understand what's happening.