【问题标题】:Java: Function with one varargs argument and function with same name and one argument of same type is allowed? [duplicate]Java:允许具有一个可变参数的函数和具有相同名称和一个相同类型参数的函数? [复制]
【发布时间】:2018-07-28 18:36:13
【问题描述】:

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

}

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

【问题讨论】:

    标签: java overloading variadic-functions function-binding


    【解决方案1】:

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

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

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

    当你只传递一个参数时,它总是会选择非可变参数方法,除非那个参数的编译时类型是一个数组:

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

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

    consumer.buy(null);
    

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

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

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

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

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

      这确保了一个方法永远不会通过变量 arity 方法调用来选择,如果它适用于通过固定 arity 方法调用。

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

    【讨论】:

      【解决方案2】:

      在您的特定情况下,如果您传递给此函数的参数是数组(还包括表示数组的逗号分隔语法),编译器只会选择 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多