为什么Java禁止将数组初始值设定项作为方法调用参数?

时间:2019-02-08 08:59:12

标签: java jls

在Java中,我们可以定义一个数组变量并像这样初始化它:

int[] prime10 = new int[] { 2, 3, 5, 7 };

在JLS中,分配的右侧称为ArrayCreationExpression。 JLS语法术语中的初始化程序为ArrayInitializer

与所有表达式一样,ArrayCreationExpression可以在方法调用参数列表中使用:

callMe(new int[] { 2, 3, 5, 7 });

但是,我们也可以使用VariableInitializer的短形式,仅使用ArrayInitializer

int[] prime10 = { 2, 3, 5, 7 };

但是我们不能在method call

中使用相同的初始化程序
// ILLEGAL IN JAVA
callMe({ 2, 3, 5, 7 });

在分析语法时,为什么编译会失败是可以理解的-JLS摘录:

VariableDeclarator:
  VariableDeclaratorId [= VariableInitializer]

VariableInitializer:
  Expression 
  ArrayInitializer

MethodInvocation:
  MethodName ( [ArgumentList] )
  // plus other variants...

ArgumentList:
  Expression {, Expression}

但是为什么要做出这样的决定?为什么不将ArrayInitializer设为Expression,或者至少在ArrayInitializer上添加带有ArgumentList的变体?显然是句法上的,还是有其他原因(可能是类型推断)阻止了这种扩展?

更新

经过一番技术上的澄清后,“如何知道{1, 2, 3}的类型”。

在方法调用中,由方法形式参数决定允许的参数类型。因此,如果我有一个方法声明:

void callMe(Number[] numbers) {
  //...
}

然后询问电话

callMe({ 1, 2, 3 }); // still ILLEGAL in Java

会平均值

callMe(new Number[] { 1, 2, 3 });

所以这里没问题。我的问题不是出于固执己见的“谁需要此东西”(无论如何谁都需要lambda,钻石和var;)-而是,从JLS的角度,或者至少从角度来看,是什么阻止(正式)这样的构造? Java架构师将此类功能引入语言的观点?

2 个答案:

答案 0 :(得分:2)

{2, 3, 5, 7}的数组类型是什么?

byte [] ???短[] ??? char [] ??? long [] ???

如果有明确说明,它就在那里。如果使用确定的任何规则来推断它,那么对于开发人员来说,这又是另一条需要学习的规则。

(PS在变量初始值设定项中,可以从变量的类型声明中推断出来。在方法调用中,不能从方法签名中推断出来,因为方法绑定的工作方式完全相反:必须先知道参数类型因为它们是确定涉及哪种方法的决定因素。)

答案 1 :(得分:2)

为什么做出这样的决定是可以理解的。您建议采用哪些规则集来推断{1、2、3}或{1,“ dasqwe”,“ c”}等的类型?造成的问题多于解决的问题。