为什么varargs应该是方法签名中的最后一个?

Rav*_*pta 21 java method-signature

如果我尝试编写如下方法

public void someStuff(Object ... args, String a )
Run Code Online (Sandbox Code Playgroud)

我收到这个错误

someStuff方法的变量参数类型Object必须是最后一个参数.

我不完全理解变量参数类型的要求是最后一个.任何输入都会有所帮助.

lin*_*ead 22

变量参数必须是最后一个,因此编译器可以确定哪个参数是哪个.

例如,假设你通过了

"测试","测试","测试","测试"

进入你的功能

public void someStuff(Object ... args, String a)
Run Code Online (Sandbox Code Playgroud)

如果您希望args变量包含3或4个字符串,Java无法解决问题.在撰写本文时,你可能会很明显,但它含糊不清.

然而,当它是相反的方式

public void someStuff(String a, Object ... args)
Run Code Online (Sandbox Code Playgroud)

Java编译器看到第一个字符串,将其粘贴到"a"中,然后知道剩余的字符串可以安全地放入args中,并且变量没有歧义.

  • 从理论上讲,这在技术上是可行的.技术问题仅在您使用3个或更多参数时开始,而varargs不是第一个或最后一个. (6认同)
  • @Balus:即使varargs处于中间位置仍然没有歧义,只是在编译器中实现的难度,但理论上它是可能的.当你有一个以上的vararg术语时,真正的问题出现了.然后你必须有回溯来解决这个问题.它基本上变得像正则表达式匹配一样难以解决. (4认同)
  • 虽然会传递一个有趣的语言功能:pass-by-regexp.`void foo(^([0-9]*)(A | B.)(bar)?$)` (3认同)
  • 这并不含糊。`String a` 不是可选的,你不能跳过它。所以第四个“test”必须是“a”。没有其他的可能。 (2认同)

MSa*_*ers 21

它遵循C惯例.反过来,C约定基于CPU架构,它在堆栈上传递参数.第一个非vararg参数以堆栈帧中的固定偏移量结束.如果您可以先放置vararg参数,则以下参数的堆栈偏移量将取决于您将传递多少个vararg参数.这将极大地复杂化访问它们所需的代码量.

在你的例子中,String a首先,它在概念上在偏移0处独立于后面的vararg参数的数量.但是对于String a最后一个,它可能在偏移args.size * 40,4,8,12 等 - 你必须每次需要时计算String a.


Mar*_*ers 9

因为这会使语言变得不必要地复杂化.想象一下,如果你还允许其他语法:

public void someStuff(String a, Object ... args, String b)
{
}
Run Code Online (Sandbox Code Playgroud)

甚至:

public void someStuff(String a, Object ... args, int b, Object ... args2)
{
}
Run Code Online (Sandbox Code Playgroud)

第二种语法意味着一个字符串后跟任意数量的Object类型的参数,后跟一个整数,后跟更多的对象.当然你可以设计一种可以接受这样的东西的语言,但是如果你还想指定args2必须包含至少一个元素,但是args可以为空呢?我们为什么不能这样做呢?你可以设计这样的语言.

归结起来,你想要规则有多复杂?在这种情况下,他们选择了满足需求的简单选项.