在准备Java认证考试时,我很惊讶看到Java允许这样做:
ChildWindow1::ChildWindow1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
}
这个类编译并运行正常。它打印"购买一个对象"两次。实际上我认为会看到编译器错误,因为可以使用这两个函数。编译器如何在此处选择最佳匹配函数?当我只传递一个参数时,它总是会选择非变量函数吗?
答案 0 :(得分:7)
方法重载分辨率有3个阶段。仅在第3阶段和最后阶段,它考虑使用varags的方法(例如您的public void buy(Object... o)
),因此如果在前2个阶段中的一个中找到匹配方法,则忽略varargs方法,并且非varag匹配方法被选中。
因此,两次调用都会导致选择public void buy(Object o)
。
当我只传递一个参数时,它总是会选择非变量函数吗?
当您只传递一个参数时,它将始终选择非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引用:
确定适用性的过程首先确定可能适用的方法(§15.12.2.1)。然后,为了确保在Java SE 5.0之前与Java编程语言兼容,该过程分三个阶段继续:
第一阶段执行重载决策而不允许装箱或拆箱转换,或使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第二阶段。
这保证了在Java SE 5.0之前在Java编程语言中有效的任何调用都不会因为引入变量arity方法,隐式装箱和/或取消装箱而被认为是不明确的。但是,变量arity方法(第8.4.1节)的声明可以更改为给定方法方法调用表达式选择的方法,因为变量arity方法在第一阶段被视为固定arity方法。例如,在已声明m(Object)的类中声明m(Object ...)会导致不再为某些调用表达式(例如m(null))选择m(Object),因为m(Object [] )更具体。
第二阶段执行重载解析,同时允许装箱和拆箱,但仍然排除使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第三阶段。
这确保了如果通过固定的arity方法调用适用,则永远不会通过变量arity方法调用选择方法。
- 醇>
第三阶段允许重载与变量arity方法,装箱和拆箱相结合。
答案 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