为什么Java不允许使用Foo(Object...)重载Foo(Object[])?

13

我想知道为什么在Java中不允许用Foo(Object... args)重载Foo(Object[] args),尽管它们以不同的方式使用?

Foo(Object[] args){}

使用方法如下:

Foo(new Object[]{new Object(), new Object()});

而另一个形式:

Foo(Object... args){}

被用作:

Foo(new Object(), new Object());

这背后有什么原因吗?


1
我可能漏掉了什么,但是你为什么需要重载呢?如果你将方法声明为void foo(Object... args),那么你可以使用foo(new Object(), new Object())或者foo(new Object[] { new Object(), new Object() })来调用它,并获得相同的结果。参见这个相关问题以获取示例。 - Daniel Pryden
vararg 只是方法签名中的一个标志,将最后声明的数组(如 int[]Object[])转换为 vararg 类型。除此之外,方法签名没有任何区别。同样的问题就像无法重载 privatepublic 方法一样。 - bestsss
2个回答

25

这篇文章15.12.2.5 选择最具体的方法讲述了这个问题,但非常复杂。例如:在Foo(Number... ints)和Foo(Integer... ints)之间进行选择。

为了保持向后兼容性,它们实际上是相同的东西。

public Foo(Object... args){} // syntactic sugar for Foo(Object[] args){}

// calls the varargs method.
Foo(new Object[]{new Object(), new Object()});
例如,您可以将main()定义为
public static void main(String... args) {
在可变参数前添加一个参数是区分它们的一种方法。
public Foo(Object o, Object... os){} 

public Foo(Object[] os) {}

Foo(new Object(), new Object()); // calls the first.

Foo(new Object[]{new Object(), new Object()}); // calls the second.
它们并不完全相同。微妙的区别是,虽然你可以将数组传递给可变参数(varargs),但你不能将数组参数视为可变参数(varargs)。
public Foo(Object... os){} 

public Bar(Object[] os) {}

Foo(new Object[]{new Object(), new Object()}); // compiles fine.

Bar(new Object(), new Object()); // Fails to compile.

此外,可变参数必须是最后一个参数。

public Foo(Object... os, int i){} // fails to compile.

public Bar(Object[] os, int i) {} // compiles ok.

+1 很好的解释。这个有没有相应的语言规范书写呢? - Eng.Fouad
请看一下这个问题:https://dev59.com/nW7Xa4cB1Zd3GeqPrppS - Eng.Fouad

3
回答这个问题最直接的方法是,同时使用这两个声明将在方法查找逻辑中创建一个歧义。如果您在同一个类中声明了两者,则在调用以下内容时将无法确定您想要哪个方法:

Object[] a = new Object[10];
Foo(a); // array or vararg?

Java要求每个方法调用必须有一个最具体的方法。

关于为什么,请参见Peter的回答。


它们完全一样,没有歧义,它们只是不能存在于同一个类中。 - bestsss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接