谁能解释为什么第一种方法优于第二种?
我知道这个重载规则(除了首先编译器找到合适的args)
代码:
public class Proba{
public static void show(Object ... args){
System.out.println("Object ...");
}
public static void show(Integer[] ... args){
System.out.println("Integer ...");
}
public static void main(String[] args) {
Integer[] array = {3,2,5,1};
show(array);
}
}
控制台:Object ...
答案 0 :(得分:4)
Java中的方法解析规则要求在尝试匹配之前>> 自动(un)装箱和变量arity > > em>那些功能。这可以确保源代码与早于这些功能的语言版本兼容。
JLS(§15.12.2)中描述了重载决策的规则:
确定适用性的过程始于确定可能性 适用的方法(§15.12.2.1)。
该过程的其余部分分为三个阶段,以确保与之兼容 Java SE 5.0之前的Java编程语言的版本。阶段是:
第一阶段(§15.12.2.2)在不允许的情况下执行重载决策 装箱或拆箱转换,或使用变量arity方法调用。 如果在此阶段没有找到适用的方法,则继续处理 进入第二阶段。 这保证了任何在Java编程语言中有效的调用 在Java SE 5.0之前,由于引入的结果不被认为是模棱两可的 变量arity方法,隐式装箱和/或拆箱。但是,宣言 变量arity方法(第8.4.1节)可以更改为给定方法选择的方法 方法调用表达式,因为变量arity方法被视为固定的 第一阶段的arity方法。例如,在类中声明m(Object ...) 已经声明m(对象)导致不再为某些人选择m(对象) 调用表达式(例如m(null)),因为m(Object [])更具体。
第二阶段(第15.12.2.3节)在允许的情况下执行重载决策 装箱和拆箱,但仍然排除使用变量arity方法 调用。如果在此阶段没有找到适用的方法则处理 继续到第三阶段。 这确保了永远不会通过变量arity方法调用来选择方法 如果它适用于固定的arity方法调用。
- 醇>
第三阶段(§15.12.2.4)允许重载与变量组合 arity方法,装箱和拆箱。
在通用方法的情况下,确定方法是否适用 (§8.4.4),要求确定类型参数。类型参数可能是 明确地或隐含地传递。如果它们被隐式传递,则必须推断它们 (§15.12.2.7)来自参数表达式的类型。
如果在三个阶段中的一个阶段确定了几种适用的方法 在适用性测试中,然后选择最具体的一个,如章节中所述 §15.12.2.5。
在您的示例中,步骤1中有两个候选项:带有Object[]
参数的方法和带有Integer[][]
参数的方法。呼叫站点的参数类型为Integer[]
。由于Object[]
可以从Integer[]
分配,但Integer[][]
不可分配,因此找到了一种适用的方法,并且重载解析在此处停止。在这种情况下,永远不会达到步骤2和3。
答案 1 :(得分:1)
15.12.2.2。第1阶段:确定通过子类型适用的匹配Arity方法
15.12.2.3。阶段2:确定方法调用转换适用的匹配Arity方法
15.12.2.4。阶段3:确定适用的变量Arity方法
在第一阶段选择 show(Object[])
,但show(Integer[]...)
只能在第3阶段选择。
如果第一个方法签名更改为show(Object[] ... args)
,您将看到预期的结果。
如果第二个方法签名更改为show(Integer ... args)
,您还会看到预期的结果。该方法也适用于阶段1,它比show(Object...)
如果我们有
public static void show(Object ... args){
System.out.println("Object ...");
}
static class IntArray{}
public static void show(IntArray ... args){
System.out.println("IntArray ...");
}
show(new IntArray());
打印预期的IntArray ...
。此处IntArray
不是Object[]
的子类型。
这太令人困惑了。程序员通常不了解这些阶段;他们考虑所有适用的方法以及其中最具体的方法。如果规范也这样做可能会更好。