Between 中的可变参数列表作为具有不同数据类型的参数
Variable Argument List in Between as a Parameter with different data type
我在使用可变参数时了解到:-
public void myMethod(String... args, int val){}
The variable argument type String of the method myMethod must be the
last parameter.
如果两者都像String
,它给出的错误是相当大的,但在这种情况下,我将int
设置为第二个参数,因此在运行时JVM
可以检查参数类型 & 可以区分为:-
myMethod("HI", "HELLO", 9)
那不可行吗。我还遗漏了任何其他会产生错误的点吗?
错误信息正确。如果你使用可变参数,它必须是最后一个参数。你可以说它可以解决问题,但它不会。只需交换参数的顺序即可。
当您在随机位置使用可变参数重载方法时,消除歧义将成为一场噩梦...(更不用说多个可变参数)。
这是在 JLS 中指定的,section 8.4.1。语言规范要求将此作为形式参数列表的一部分:
FormalParameterList:
ReceiverParameter
FormalParameters , LastFormalParameter
LastFormalParameter
LastFormalParameter
标记是可变参数定义和允许的地方。
LastFormalParameter:
{VariableModifier} UnannType {Annotation} ... VariableDeclaratorId
FormalParameter
关注...
。这是形式参数语法中唯一允许这样做的地方。 FormalParameters
没有这个余地。
FormalParameters:
FormalParameter {, FormalParameter}
ReceiverParameter {, FormalParameter}
语言设计者选择禁止这样做的原因有很多:
- 区分必须由编译器完成,因为可变参数完全是编译器的一个特性。它们只是转换为隐式数组构造函数。
您的示例在理论上可行,但限制会非常严格:例如,编译器很难在这种情况下看到第一个可变参数参数的结束位置
void foo(Object... objs, String... s)
foo("a", "b", "c")
另一个例子是这样的:
void bar(int... ints, long... longs)
foo(1, 2, 3, 4)
您可能会争辩说 int
和 long
是不同的数据类型,但不幸的是,由于扩大转换,可以在预期 long
的地方使用整数。另一个例子涉及拳击:
void baz(Object... objs, int... ints)
baz(1, 2, 3, 4)
int
和Object
没有直接关系,但是int
可以转化为Integer
,是Object
的子类。
重载的方法和可变参数越多,情况就变得越复杂。
- 有点技术性,但仍然相关:在字节码中,
varargs
不是参数属性,而是方法修饰符标志(ACC_VARARGS
)。这意味着方法要么是可变的(最后一个参数是可变参数)要么不是。
- 如果您确实需要在您的方法中使用可变参数,请将其移至最后一个位置。唯一不能这样做的情况是当你有多个可变参数时,这是不可能的。
- 如果编译器允许您在声明端执行此操作而不会出错,那么在使用端几乎不可能出现有用的错误。
String...
与String[]
相同,只是您不需要在使用位置创建数组。你可以声明一个方法
void foo(String[] strings, int i)
并将其命名为
void foo({ "a", "b" }, 2)
只需再敲击 2 次按键,并且没有可变参数参数引入的所有麻烦。
我已经在 JVM-language 编译器上工作了一年多了,我也考虑过添加这个功能。但是,方法解析系统 已经 极其复杂(我决定包括自定义 infix
和 prefix
运算符/方法以及命名和默认参数并没有使它更容易),并且多个可变参数不会使它更容易。
我在使用可变参数时了解到:-
public void myMethod(String... args, int val){}
The variable argument type String of the method myMethod must be the last parameter.
如果两者都像String
,它给出的错误是相当大的,但在这种情况下,我将int
设置为第二个参数,因此在运行时JVM
可以检查参数类型 & 可以区分为:-
myMethod("HI", "HELLO", 9)
那不可行吗。我还遗漏了任何其他会产生错误的点吗?
错误信息正确。如果你使用可变参数,它必须是最后一个参数。你可以说它可以解决问题,但它不会。只需交换参数的顺序即可。
当您在随机位置使用可变参数重载方法时,消除歧义将成为一场噩梦...(更不用说多个可变参数)。
这是在 JLS 中指定的,section 8.4.1。语言规范要求将此作为形式参数列表的一部分:
FormalParameterList: ReceiverParameter FormalParameters , LastFormalParameter LastFormalParameter
LastFormalParameter
标记是可变参数定义和允许的地方。
LastFormalParameter: {VariableModifier} UnannType {Annotation} ... VariableDeclaratorId FormalParameter
关注...
。这是形式参数语法中唯一允许这样做的地方。 FormalParameters
没有这个余地。
FormalParameters: FormalParameter {, FormalParameter} ReceiverParameter {, FormalParameter}
语言设计者选择禁止这样做的原因有很多:
- 区分必须由编译器完成,因为可变参数完全是编译器的一个特性。它们只是转换为隐式数组构造函数。
您的示例在理论上可行,但限制会非常严格:例如,编译器很难在这种情况下看到第一个可变参数参数的结束位置
void foo(Object... objs, String... s) foo("a", "b", "c")
另一个例子是这样的:
void bar(int... ints, long... longs) foo(1, 2, 3, 4)
您可能会争辩说
int
和long
是不同的数据类型,但不幸的是,由于扩大转换,可以在预期long
的地方使用整数。另一个例子涉及拳击:void baz(Object... objs, int... ints) baz(1, 2, 3, 4)
int
和Object
没有直接关系,但是int
可以转化为Integer
,是Object
的子类。重载的方法和可变参数越多,情况就变得越复杂。
- 有点技术性,但仍然相关:在字节码中,
varargs
不是参数属性,而是方法修饰符标志(ACC_VARARGS
)。这意味着方法要么是可变的(最后一个参数是可变参数)要么不是。 - 如果您确实需要在您的方法中使用可变参数,请将其移至最后一个位置。唯一不能这样做的情况是当你有多个可变参数时,这是不可能的。
- 如果编译器允许您在声明端执行此操作而不会出错,那么在使用端几乎不可能出现有用的错误。
String...
与String[]
相同,只是您不需要在使用位置创建数组。你可以声明一个方法void foo(String[] strings, int i)
并将其命名为
void foo({ "a", "b" }, 2)
只需再敲击 2 次按键,并且没有可变参数参数引入的所有麻烦。
我已经在 JVM-language 编译器上工作了一年多了,我也考虑过添加这个功能。但是,方法解析系统 已经 极其复杂(我决定包括自定义 infix
和 prefix
运算符/方法以及命名和默认参数并没有使它更容易),并且多个可变参数不会使它更容易。