我有两个重载方法:foo
和bar
//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[]
{}可以隐式投放Object
和Object[]
。
答案 0 :(得分:3)
在第一种情况下,args的类型实际上是Integer [] [],即你的数组被varargs装入另一个数组。编译器选择Integer []版本,因为它是最具体的类型。
在第二种情况下,args == i并且是一个Integer []。在这种情况下,编译器必须选择将它包装在一个新数组中以调用Integer [] ...版本,或者只是将Integer []转换为Object []。它选择了第二个,因为这是规则。
故事的寓意是:不要超载varargs方法 - 这让人感到困惑。
答案 1 :(得分:3)
这基本上是编译器决定在所有方法中调用最具体的方法。
致电时
System.out.println(foo(i));//Object[]... vs Integer[]...
它会调用foo(Integer[]... args)
因为在运行时,JVM使用Integer[][]
参数委托对方法的调用,而使用varags指定的不使用Object[][]
param 方法。因为使用Integer [] []而不是Object [] []。
在后面的陈述中,当你打电话
System.out.println(bar(i));//Object... vs Integer[]...
它将转到bar(Object... args)
再次使用varags,param的类型将是Object []而不是Object [] []。编译器将再次调用最具体的方法,即具有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更准确,
这意味着将对具有Integer [] []而不是Object [] []的方法调用Integer []。 其中Integer []的调用将发送到Object []而不是Integer [] []。
请参阅here以选择最具体的方法。