重载var-args

时间:2013-10-30 20:56:11

标签: java overloading variadic-functions

谁能解释为什么第一种方法优于第二种?

我知道这个重载规则(除了首先编译器找到合适的args)

  1. 拓宽
  2. 自动装箱
  3. 无功ARGS
  4. 代码:

    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 ...

2 个答案:

答案 0 :(得分:4)

Java中的方法解析规则要求在尝试匹配之前> 自动(un)装箱和变量arity em>那些功能。这可以确保源代码与早于这些功能的语言版本兼容。

JLS(§15.12.2)中描述了重载决策的规则:

  

确定适用性的过程始于确定可能性   适用的方法(§15.12.2.1)。

     

该过程的其余部分分为三个阶段,以确保与之兼容   Java SE 5.0之前的Java编程语言的版本。阶段是:

     
      
  1. 第一阶段(§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 [])更具体。

  2.   
  3. 第二阶段(第15.12.2.3节)在允许的情况下执行重载决策   装箱和拆箱,但仍然排除使用变量arity方法   调用。如果在此阶段没有找到适用的方法则处理   继续到第三阶段。   这确保了永远不会通过变量arity方法调用来选择方法   如果它适用于固定的arity方法调用。

  4.   
  5. 第三阶段(§15.12.2.4)允许重载与变量组合   arity方法,装箱和拆箱。

  6.         

    在通用方法的情况下,确定方法是否适用   (§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[]的子类型。


这太令人困惑了。程序员通常不了解这些阶段;他们考虑所有适用的方法以及其中最具体的方法。如果规范也这样做可能会更好。