2015-11-01 71 views
11

我有两个重载方法:foobar重载可变参数数组,选择方法

//Object[]... vs Integer[]... 
public static String foo(Object[]... args) { return "Object[] args"; } 
public static String foo(Integer[]... args) { return "Integer[] args";} 

//Object... vs Integer[]... 
public static String bar(Object... args) {return "Object args";} 
public static String bar(Integer[]... args) {return "Integer[] args";} 

现在,当我使用它们,如:

Integer[] i = { 5 }; 
System.out.println(foo(i));//Object[]... vs Integer[]... 
System.out.println(bar(i));//Object... vs Integer[]... 

我越来越

Integer[] args 
Object args 

这是一个问题:为什么我们有两个不同的输出?
Integer[]可以隐式投射到ObjectObject[]

+2

对于那些想玩夏洛克[15.12.2.5。选择最具体的方法](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5) – Pshemo

+0

您至少应该提及编译器警告。 –

+0

@Colonel,是的,你可以,是的,你可以。当你尝试时你会得到一个运行时异常。 –

回答

3

这基本上是编译器决定调用中所有最具体的方法。

当你调用

System.out.println(foo(i));//Object[]... vs Integer[]... 

它会调用foo(Integer[]... args)

因为在运行时,JVM代表的调用方法与Integer[][]参数和Object[][] PARAM方法,通过varags规定。因为使用Integer [] []而不是Object [] []调用方法会更具体。


在后来的声明,当你调用

System.out.println(bar(i));//Object... vs Integer[]...

它会去bar(Object... args)

再次使用varags,PARAM的类型将对象[],而不是目的[][]。再次编译器会调用,这将是具有Object... args所述一个最具体的方法。

如果更改按以下删除varags方法签名:

//Object... vs Integer[]... 
    public static String bar(Object args) { 

     return "Object args"; 
    } 

    public static String bar(Integer[] args) { 
     return "Integer[] args"; 
    } 

,那么你会发现,它会调用bar(Integer[] args),因为它是更具体的方法调用。

所以要按照JLS Subtyping among Array Types更精确,

  • 如果S和T都引用类型,则S []> T []当且仅当S> T.
  • 对象>对象[]

这意味着整数[]的呼叫将要方法由具有整数[] [],而不是对象[] []。 Integer []的调用将被设置为Object []而不是Integer [] []。

请参阅here选择最具体的方法。

3

在第一种情况,args来类型实际上是整数[] [],即,您的阵列盒装成由可变参数另一阵列。编译器选择Integer []版本,因为它是最具体的类型。

在第二种情况下,ARGS == i和是一个Integer []。在这种情况下,编译器必须选择将它包装在一个新的数组中以调用Integer [] ...版本,或者只是将Integer []转换为Object []。它选择了第二个,因为这是规则。

这个故事的寓意是:不要超载可变参数的方法 - 这是令人困惑的。

+1

你能找到说'这是规则'的规格位吗? –

+0

我可以......但是OP已经用他的编译器证明了它:) –

+0

如果你能找到它,我会赞成。我无法破译它。 –