问题
While preparing for Java certification exam I was quite surprised to see that Java allows this:
public class Consumer {
public void buy(Object o) {
System.out.println("Buying one object");
}
public void buy(Object... o) {
System.out.println("Buying multiple objects");
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.buy(new Object());
consumer.buy("a String");
}
}
This class compiles and runs fine. It prints "Buying one object" two times. Actually I thought to see a compiler error because both functions could be used. How does the compiler select the best matching function here? Will it always select the non-varargs function when I pass only one argument?
回答1:
Method overloading resolution has 3 stages. Only on the 3rd and last stage it considers methods with varags (such as your public void buy(Object... o)
), so if a matching method is found in one of the first 2 stages, the varargs methods are ignored, and the non-varag matching method is chosen.
Therefore both calls result in public void buy(Object o)
being chosen.
Will it always select the non-varargs function when I pass only one argument?
It will always select the non-varargs method when you pass only one argument, unless the compile time type of that argument is an array:
Object[] arr = new Object[]{"a string"};
consumer.buy(arr);
Passing null
will also cause the compiler to select the varargs method:
consumer.buy(null);
Here's the relevant JLS 15.12.2. Compile-Time Step 2: Determine Method Signature quote:
The process of determining applicability begins by determining the potentially applicable methods (§15.12.2.1). Then, to ensure compatibility with the Java programming language prior to Java SE 5.0, the process continues in three phases:
The first phase performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null)), as m(Object[]) is more specific.
The second phase performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.
This ensures that a method is never chosen through variable arity method invocation if it is applicable through fixed arity method invocation.
The third phase allows overloading to be combined with variable arity methods, boxing, and unboxing.
回答2:
In your particular case the compiler will only select buy(Object... o)
if the argument you pass to this function is an array (which also includes the comma-delimited syntax that represents an array). For instance:
Object o1 = new Object();
Object o2 = new Object();
Object[] oArray = new Object[]{o1, o2};
buy((Object[]) null); // will call the varargs function
buy(new Object[]{o1}); // will call the varargs function
buy(oArray); // will call the varargs function
buy(o1, o2); // will call the varargs function
buy((Object) null); // will call the non-varargs function
buy(o1); // will call the non-varargs function
来源:https://stackoverflow.com/questions/48850699/java-function-with-one-varargs-argument-and-function-with-same-name-and-one-arg