Java: 允许具有一个可变参数的函数和具有相同名称和一个相同类型参数的函数吗?

Java: Function with one varargs argument and function with same name and one argument of same type is allowed?

在准备 Java 认证考试时,我很惊讶地看到 Java 允许这样做:

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

}

这个 class 可以正常编译和运行。它打印 "Buying one object" 两次。实际上我想看到一个编译器错误,因为这两个函数都可以使用。编译器如何select这里的最佳匹配函数?当我只传递一个参数时,它总是 select 非可变参数函数吗?

方法重载决议有 3 个阶段。仅在第 3 个和最后一个阶段,它会考虑带有可变参数的方法(例如您的 public void buy(Object... o)),因此如果在前两个阶段之一找到匹配方法,可变参数方法将被忽略,并且 non-varag选择了匹配方式。

因此两次调用都会导致 public void buy(Object o) 被选中。

Will it always select the non-varargs function when I pass only one argument?

当你只传递一个参数时,它总是 select non-varargs 方法,除非该参数的编译时类型是数组:

Object[] arr = new Object[]{"a string"};
consumer.buy(arr);

传递 null 也会导致编译器 select 可变参数方法:

consumer.buy(null);

这是相关的 JLS 15.12.2. Compile-Time Step 2: Determine Method Signature 引述:

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:

  1. 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.

  2. 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.

  3. The third phase allows overloading to be combined with variable arity methods, boxing, and unboxing.

在您的特定情况下 如果您传递给此函数的参数是一个数组(其中还包括 select buy(Object... o) 编译器将只=16=] 表示数组的语法)。例如:

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