如果我尝试编写如下方法
public void someStuff(Object ... args, String a )
我收到此错误
someStuff方法的变量参数类型Object必须是最后一个参数。
我不完全理解变量参数类型的要求是最后一个。 任何输入都会有所帮助。
答案 0 :(得分:21)
变量参数必须是最后一个,因此编译器可以确定哪个参数是哪个。
例如,假设您通过了
“测试”,“测试”,“测试”,“测试”
进入你的功能
public void someStuff(Object ... args, String a)
如果您希望args变量包含3或4个字符串,则Java无法解决问题。在撰写本文时,你可能会很明显,但这很模糊。
然而,当它是相反的时候
public void someStuff(String a, Object ... args)
Java编译器看到第一个字符串,将其粘贴到“a”中,然后知道剩下的字符串可以安全地放入args中,并且变量没有歧义。
答案 1 :(得分:21)
遵循C惯例。反过来,C约定基于CPU架构,它在堆栈上传递参数。第一个非vararg参数以堆栈帧中的固定偏移量结束。如果您可以先放置vararg参数,则以下参数的堆栈偏移量将取决于您将传递多少个vararg参数。这将极大地复杂化访问它们所需的代码量。
在您的示例中,首先使用String a
,它在概念上在偏移0处独立于后面的vararg参数的数量。但最后String a
可能会偏移0,4,8,12等 - 每次需要args.size * 4
时,您必须计算String a
。
答案 2 :(得分:9)
因为这会使语言变得不必要地复杂化。想象一下,如果你还允许其他语法:
public void someStuff(String a, Object ... args, String b)
{
}
甚至:
public void someStuff(String a, Object ... args, int b, Object ... args2)
{
}
第二种语法是指一个字符串,后跟任意数量的Object类型的参数,后跟一个整数,后跟更多的对象。当然你可以设计一种可以接受这样的东西的语言,但是如果你还想指定args2必须包含至少一个元素,但是args可以为空呢?我们为什么不能这样做呢?你可以设计这样一种语言。
归结起来,你想要规则有多复杂?在这种情况下,他们选择了一个满足需求的简单选项。
答案 3 :(得分:3)
一个String也是Object的一个实例,所以如果你使用varargs你的vararg数组必须是最后一个参数,因为编译器无法真正决定什么是args以及你的字符串a是什么。将方法调用视为方法名称的元组和作为参数的对象列表。如果您有两种方法:
public void someStuff(Object ... args, String a )
public void someStuff(String a, String b)
编译器无法决定为someStuff选择什么方法(“Hello”,“Hello”)。 如果将String a作为第一个参数,则可以确定someStuff(String,String)比someStuff(String,Object)更具体。
答案 4 :(得分:0)
考虑如何使用var args的方法,任何其他格式都可能导致含糊不清。让varargs持续可以防止可能的歧义,而无需额外的语法来解决歧义,这会降低该功能的好处。
考虑以下方法声明:
public void varargsAreCool(String surname, String firstname,
String... nicknames) {
// some cool varargs logic
}
当像varargsAreCool("John", "Smith")
一样使用时,显然John Smith
没有昵称。使用时如varargsAreCool("Andrew", "Jones", "The Drew", "Jonesy")
。
现在考虑以下无效方法声明:
public void varargsAreCool(String surname, String... nicknames,
String firstname) {
// some cool varargs logic
}
像varargsAreCool("John", "Smith")
一样使用Smith
John的昵称或姓氏?如果是他的姓,我怎么表明他没有绰号?要做到这一点,你可能不得不使用像varargsAreCool("John", new String[]{}, "Smith")
这样的方法,这种方法很笨拙,并且在某种程度上违背了该功能的目的。
如果像varargsAreCool("Andrew", "The Drew", "Jonesy", "Jones")
那样使用The Drew, Jonesy and Jones
所有昵称且姓氏丢失了吗?同样,这种模糊性可以解决,但代价是笨重的额外语法。
答案 5 :(得分:0)
这是 GeekOnJava 文章中的第五条规则:
如上所述,准备数组对象,如果我们愿意的话 将var-args声明为第一个或第二个参数编译器不具备的 线索有多少参数必须包含在数组对象中。
根据第五条规则:
我们不能声明多个var-arg参数,即使它们是不同的类型。因为,编译器不知道必须创建多少个值的var-arg数组对象。 这会导致编译时错误。
public void add(int... a,int...b){}//leads compile time error
public void add(int... a,long...b){} //compile time error
在上面的场景编译器中说 -
方法add的变量参数类型int必须是最后一个 参数