Varargs Java Ambiguous Call

雨燕双飞 提交于 2019-11-26 17:32:08

问题


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;
}

回答1:


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) and sum(double... args), the signature sum(int... args) is more specific because any invocation of that method could also be passed on to sum(double... args) by applying a widening conversion. The same does not hold for a sum(boolean... args) method, which cannot be similarly converted.

Java Language Specification, SE 8 version:

15.12. Method Invocation Expressions

15.12.2.5. Choosing the Most Specific Method

The Java programming language uses the rule that the most specific method is chosen.

...

One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:

...

  • m2 is not generic, and m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ n, n = k).

...

A type S is more specific than a type T for any expression if S <: T (§4.10).


4.10. Subtyping

4.10.1. Subtyping among Primitive Types

double >1 float

float >1 long

long >1 int




回答2:


As mentioned in this answer, there are rules followed when selecting which overloaded method to use.

To quote:

  1. Primitive widening uses the smallest method argument possible
  2. Wrapper type cannot be widened to another Wrapper type
  3. You can Box from int to Integer and widen to Object but no to Long
  4. Widening beats Boxing, Boxing beats Var-args.
  5. You can Box and then Widen (An int can become Object via Integer)
  6. You cannot Widen and then Box (An int cannot become Long)
  7. You cannot combine var-args, with both widening and boxing.

(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 a double is represented by a decimal-number with precision 32 bytes more than that of a float (e.g. 1.0), we can say that ints are "less than" or "smaller than" doubles, and by that logic, ints can be "promoted" to doubles and doubles can be "demoted" to ints.

Put simply, a primitive that can be widened to another primitive (e.g. int -> float -> double) is more specific than another. For example, an int is more specific than a double because 1 can be promoted to 1.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 ints and booleans (types that cannot be widened to each other) respectively, the compiler now cannot choose a method to use since ints cannot be "promoted" or "demoted" like ints, floats and doubles. Therefore, it will throw a compile error.

I hope this helps you to understand what's happening.



来源:https://stackoverflow.com/questions/31627236/varargs-java-ambiguous-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!