有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

重载Java:允许使用一个varargs参数的函数和具有相同名称和一个相同类型参数的函数?

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

}

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


共 (2) 个答案

  1. # 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
    
  2. # 2 楼答案

    方法重载解析分为3个阶段。只有在第三个也是最后一个阶段,它才会考虑使用varag的方法(例如public void buy(Object... o)),因此,如果在前两个阶段中的一个阶段中找到匹配方法,则会忽略varargs方法,并选择非varag匹配方法

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

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

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

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

    传递null还将导致编译器选择varargs方法:

    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.