如果我尝试编写如下方法
public void someStuff(Object ... args, String a )
我收到这个错误
方法 someStuff 的变量参数类型 Object 必须是最后一个参数。
我不完全理解变量参数类型的要求是最后一个。任何输入都会有所帮助。
如果我尝试编写如下方法
public void someStuff(Object ... args, String a )
我收到这个错误
方法 someStuff 的变量参数类型 Object 必须是最后一个参数。
我不完全理解变量参数类型的要求是最后一个。任何输入都会有所帮助。
变量参数必须是最后一个,以便编译器可以计算出哪个参数是哪个。
例如,假设您通过
“测试”、“测试”、“测试”、“测试”
进入你的功能
public void someStuff(Object ... args, String a)
如果您希望 args 变量包含 3 或 4 个字符串,Java 无法解决。在撰写本文时,这对您来说可能是显而易见的,但它是模棱两可的。
然而,当它反过来
public void someStuff(String a, Object ... args)
Java 编译器看到第一个字符串,将其粘贴到“a”中,然后知道剩余的字符串可以安全地放入 args 并且变量没有歧义。
它遵循 C 约定。反过来,C 约定基于在堆栈上传递参数的 CPU 架构。第一个非可变参数最终在堆栈帧中的固定偏移量处结束。如果您可以将可变参数放在第一位,则以下参数的堆栈偏移量将取决于您将传递多少可变参数。这将使访问它们所需的代码量大大复杂化。
在您的示例中,String a
首先,它在概念上位于偏移量 0 处,与后面的 vararg 参数的数量无关。但String a
最后,它可能位于偏移量 0、4、8、12 等处 - 您必须在args.size * 4
每次需要时进行计算String a
。
因为那会使语言变得不必要地复杂。想象一下,如果您还允许其他语法:
public void someStuff(String a, Object ... args, String b)
{
}
甚至:
public void someStuff(String a, Object ... args, int b, Object ... args2)
{
}
第二种语法意味着一个字符串后跟任意数量的 Object 类型的参数,然后是一个整数,然后是更多对象。当然,您可以设计一种可以接受此类内容的语言,但是如果您还想指定 args2 必须包含至少一个元素,但 args 可以为空怎么办?为什么我们也不能这样做?你可以设计这样一种语言。
归结为,您希望规则有多复杂?在这种情况下,他们选择了一个满足需求的简单选项。
好吧,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) 更具体。
考虑到如何使用带有 var args 的方法,任何其他格式都可能导致歧义。将可变参数放在最后可以防止可能的歧义,而无需额外的语法来解决歧义,这会降低功能的好处。
考虑以下方法声明:
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
昵称或姓氏一样使用?如果是他的姓,我怎么表示他没有昵称?要做到这一点,您可能不得不使用这样的方法,这种方法varargsAreCool("John", new String[]{}, "Smith")
很笨拙,并且在某种程度上违背了该功能的目的。
当这样使用varargsAreCool("Andrew", "The Drew", "Jonesy", "Jones")
时,The Drew, Jonesy and Jones
所有的昵称和姓氏都不见了?同样,这种歧义可以得到解决,但代价是笨拙的附加语法。