为什么可变参数应该是方法签名中的最后一个?
如果我尝试编写如下方法,
public void someStuff(Object ... args, String a )
我会收到此错误
someStuff方法的变量参数类型Object必须是最后一个参数。
我不完全理解变量参数类型是最后一个的要求。 任何输入都会有帮助。
If I try to write a method like below
public void someStuff(Object ... args, String a )
I get this error
The variable argument type Object of the method someStuff must be the last parameter.
I don't fully understand the requirement of variable argument type to be the last.
Any inputs will be helpful.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
它遵循 C 约定。 C 约定又基于在堆栈上传递参数的 CPU 架构。第一个非 vararg 参数最终位于堆栈帧中的固定偏移处。如果您可以将 vararg 参数放在前面,则以下参数的堆栈偏移量将取决于您要传递的 vararg 参数的数量。这将使访问它们所需的代码量变得非常复杂。
在您的示例中,首先使用
String a
,从概念上讲,它位于偏移量 0 处,与后面的 vararg 参数的数量无关。但是如果String a
最后,它可能位于偏移量 0、4、8、12 等处 - 每次需要时都必须计算args.size * 4
字符串a
。It follows the C convention. The C convention in turn is based on CPU architectures which pass arguments on the stack. The first non-vararg arguments end up at a fixed offset in the stackframe. If you could put the vararg arguments first, the stack offset of the following arguments would depend on how many vararg parameters you would have passed. This would greatly complicate the amount of code needed to access them.
In your example, with
String a
first, it's conceptually at offset 0 independent how the number of vararg arguments that follow. But withString a
last, it could be at offset 0, 4, 8, 12 etc - you'd have to calculateargs.size * 4
everytime you neededString a
.变量参数必须是最后一个,以便编译器可以计算出哪个参数是哪个。
例如,假设您将
“test”、“test”、“test”、“test”
传递到函数中,
如果您希望 args 变量包含 3 或 4 个字符串,Java 将无法正常工作。在撰写本文时,这对您来说可能是显而易见的,但它是模糊的。
然而,当情况相反时,
Java 编译器看到第一个字符串,将其粘贴到“a”中,然后知道剩余的字符串可以安全地放入 args 中,并且变量上没有歧义。
The variable argument has to be the last so the compiler can work out which argument is which.
For example, say you pass
"test", "test", "test", "test"
into your function
Java cannot work out if you want the args variable to contain 3 or 4 strings. It may be obvious to you at the time of writing but it's ambiguous.
However, when it's the other way around
The Java compiler sees the first string, stick it into "a" and then knows that the remaining strings can be safely put into args and there is no ambiguity over the variables.
因为这会使语言变得不必要的复杂。想象一下,如果您还允许其他语法:
或者甚至:
第二种语法意味着一个字符串,后跟任意数量的
Object
类型的参数,后跟一个整数,再后跟更多对象。当然,您可以设计一种可以接受此类内容的语言,但如果您还想指定 args2 必须至少包含一个元素,但 args 可以为空,该怎么办?为什么我们也不能这样做呢?您可以设计这样一种语言。归根结底,你希望规则有多复杂?在这种情况下,他们选择了一个可以满足需求的简单选项。
Because that would make the language unnecessarily complex. Imagine if you also allowed other syntaxes:
Or even:
This second syntax means a string followed by any number of arguments of type
Object
, followed by an integer, followed by more objects. Sure you could design a language that could accept things like that, but what if you also wanted to specify that theargs2
must contain at least one element, butargs
can be empty? Why can't we do that too? You could design such a language.It boils down to, how complicated do you want the rules to be? In this case they chose a simple option that fulfils the needs.
嗯,
String
也是Object
的实例,因此如果您使用可变参数,则可变参数数组必须是最后一个参数,因为编译器无法真正决定什么是args
,你的字符串a
是什么。将方法调用视为方法名称的元组和作为参数的对象列表。如果您有这样的两种方法:编译器无法决定选择哪种方法
someStuff("Hello", "Hello")
。如果您将
String a
作为第一个参数,它可以确定someStuff(String, String)
比someStuff(String, Object)
更具体>。Well, a
String
is also an instance ofObject
, so if you are using varargs, your vararg array has to be the last parameter because the compiler can't really decide what isargs
and what is your stringa
. Think of the method call as a tuple of method name and a list of objects which are your parameters. If you have two methods like so:The compiler couldn't decide what method to choose for
someStuff("Hello", "Hello")
.If you put your
String a
as the first argument it can decide thatsomeStuff(String, String)
is more specific thansomeStuff(String, Object)
.鉴于如何使用带有 var args 的方法,任何其他格式都可能导致歧义。将可变参数放在最后可以防止可能的歧义,而不需要额外的语法来解决歧义,这会减少该功能的优势。
考虑以下方法声明:
当像
varargsAreCool("John", "Smith")
这样使用时,很明显John Smith
没有昵称。当像这样使用时varargsAreCool("Andrew", "Jones", "The Drew", "Jonesy")
。现在考虑以下无效方法声明:
当像
varargsAreCool("John", "Smith")
使用时,Smith
是 John 的昵称还是姓氏?如果是他的姓氏,我如何表明他没有昵称?为此,您可能必须使用像varargsAreCool("John", new String[]{}, "Smith")
这样的方法,该方法很笨拙,并且在某种程度上违背了该功能的目的。像这样使用时,
varargsAreCool("Andrew", "The Drew", "Jonesy", "Jones")
是The Drew、Jonesy 和 Jones
所有昵称和姓氏失踪了?同样,这种歧义可以得到解决,但代价是笨重的附加语法。Given how a method with var args is used any other format could lead to ambiguities. Having the varargs last prevents possible ambiguities without requiring additional syntax to resolve the ambiguities which would lessen the benefit of the feature.
Consider the follow method declaration:
When used like
varargsAreCool("John", "Smith")
it is obvious thatJohn Smith
has no nicknames. When used like thisvarargsAreCool("Andrew", "Jones", "The Drew", "Jonesy")
.Now consider the following invalid method declaration:
When used like
varargsAreCool("John", "Smith")
isSmith
John's nickname or his surname? If it is his surname how do I indicate that he has no nicknames? To do this you would probably have to use the method like thisvarargsAreCool("John", new String[]{}, "Smith")
which is clunky and somewhat defeats the purpose of the feature.When used like this
varargsAreCool("Andrew", "The Drew", "Jonesy", "Jones")
are theThe Drew, Jonesy and Jones
all nicknames and the surname is missing? Again this ambiguity could be resolved but at the cost of clunky additional syntax.