2

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

}

这个类编译并运行良好。它会打印两次“Buying one object”。实际上我想看到一个编译器错误,因为这两个函数都可以使用。编译器如何在这里选择最佳匹配函数?当我只传递一个参数时,它是否总是选择非可变参数函数?

4

2 回答 2

9

方法重载解析有 3 个阶段。只有在第 3 个和最后一个阶段,它才考虑带有可变参数的方法(例如 your public void buy(Object... o)),因此如果在前 2 个阶段之一中找到匹配方法,则忽略可变参数方法,并选择非可变参数匹配方法。

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

当我只传递一个参数时,它是否总是选择非可变参数函数?

当您只传递一个参数时,它将始终选择非可变参数方法,除非该参数的编译时类型是数组:

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

传递null也会导致编译器选择 varargs 方法:

consumer.buy(null);

这是相关的JLS 15.12.2。编译时步骤 2:确定方法签名报价:

确定适用性的过程从确定可能适用的方法开始(§15.12.2.1)。然后,为确保与 Java SE 5.0 之前的 Java 编程语言兼容,该过程将分三个阶段进行:

  1. 第一阶段执行重载决议,不允许装箱或拆箱转换,或使用变量 arity 方法调用。如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

    这保证了在 Java SE 5.0 之前在 Java 编程语言中有效的任何调用都不会因为引入可变参数方法、隐式装箱和/或拆箱而被视为模棱两可。但是,变量 arity 方法的声明(第 8.4.1 节)可以更改为给定方法方法调用表达式选择的方法,因为变量 arity 方法在第一阶段被视为固定 arity 方法。例如,在已经声明 m(Object) 的类中声明 m(Object...) 会导致不再为某些调用表达式(例如 m(null))选择 m(Object),如 m(Object[] ) 更具体。

  2. 第二阶段执行重载解决方案,同时允许装箱和拆箱,但仍排除使用可变参数方法调用。如果在此阶段没有找到适用的方法,则处理继续到第三阶段。

    这确保了一个方法永远不会通过可变的方法调用来选择,如果它可以通过固定的方法调用来应用的话。

  3. 第三阶段允许将重载与可变数量方法、装箱和拆箱相结合。

于 2018-02-18T10:39:22.340 回答
1

在您的特定情况下,编译器只会选择buy(Object... o)您传递给此函数的参数是数组(还包括表示数组的逗号分隔语法)。例如:

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
于 2018-02-18T10:42:35.990 回答