形式参数类型声明中double ...和double []之间的区别

时间:2010-05-22 13:48:47

标签: java arrays variadic-functions parameter-passing

我有疑问:这两个声明有什么区别?

 public static void printMax(double... numbers) { ... }

 public static void printmax(double numbers[])  { ... }

double... numbersdouble numbers[]相同吗?

3 个答案:

答案 0 :(得分:8)

关于varargs

方法参数声明中的Type...构造通常称为varargs。在JLS中,它被称为变量arity 参数。

JLS 8.4.1 Format parameters

  

列表中的最后一个正式参数是特殊的;它可能是变量arity 参数,由类型后面的省略号表示。

     

如果最后一个形式参数是类型为T的变量arity参数,则认为它定义了T[]类型的形式参数。然后该方法是变量arity 方法。否则,它是固定arity 方法。变量arity方法的调用可能包含比形式参数更多的实际参数表达式。将评估与变量arity参数之前的形式参数不对应的所有实际参数表达式,并将结果存储到将传递给方法调用的数组中。

为了在代码中说明,这是varargs允许您执行的操作:

static void f(int... nums) {
    for (int num : nums) {
        System.out.println(num);
    }
}
//...

f(1,2,3); // prints "1", "2", "3"

相反,如果没有varargs结构,你必须这样做:

static void g(int[] nums) {
    for (int num : nums) {
        System.out.println(num);
    }       
}
//...

g(new int[] { 1, 2, 3 }); // prints "1", "2", "3"

varargs是一种所谓的语法糖,可以隐藏你的冗长。

回到你的问题,printMax(double... numbers)printmax(double numbers[])之间的区别在于第一个是变量arity 方法,这意味着你可以给它一个变量号参数。后者是一个固定arity 方法,这意味着它将接受一个且唯一的参数。

请注意上面关于T...真的是T[]的引用。也就是说,即使使用varargs,您仍然可以执行以下操作:

f(new int[] { 1, 2, 3 }); // prints "1", "2", "3"

在这里,您手动创建数组以保存vararg参数。事实上,如果你去反编译代码,你会发现,就像JLS指定的那样,f实际上确实采用int[]参数,而f(1, 2, 3)实现为{{ 1}}。

另见


Varargs陷阱

如何解决varargs是非常复杂的,有时它会让你感到惊讶。

考虑这个例子:

f(new int[] { 1, 2, 3 })

由于varargs的解析方式,最后一个语句会调用static void count(Object... objs) { System.out.println(objs.length); } count(null, null, null); // prints "3" count(null, null); // prints "2" count(null); // throws java.lang.NullPointerException!!! ,这当然会导致objs = null NullPointerException。如果要为varargs参数提供一个objs.length参数,可以执行以下任一操作:

null

相关问题

以下是人们在处理varargs时提出的一些问题的示例:


何时使用varargs

如前一节所示,varargs可能很棘手。但是,在适当的情况下使用它们可以使代码更加简洁。

以下是 Effective Java 2nd Edition的引用,第42项:明智地使用varargs (作者强调):

  

教训很清楚。 不要改进每个具有最终数组参数的方法;当呼叫真正对可变长度值序列进行操作时,仅使用varargs

varargs不仅容易混淆,而且成本也很高。 Effective Java 2nd Edition 实际上建议为最常见的使用场景提供固定的重载。

  

假设您已确定95%的方法调用具有三个或更少的参数。然后声明方法的五个过载,每个过载一个零到三个普通参数,以及一个参数个数超过三个时使用的变量。

这本书的深度更深入,但基本上你应该只在实际有意义的时候使用varargs。即使在这些情况下,出于性能原因,您仍可能需要考虑提供固定过载。

相关问题

API链接

以下是varargs有意义的一些例子:


关于数组声明

请,请不要养成这样声明数组的习惯:

count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"

您应该使用类型而不是标识符放置括号:

int x[];

请注意,这也是上述讨论中引用数组的方式,例如: int[] x; T[]等。

相关问题

答案 1 :(得分:2)

主要区别在于,在第一种情况下,您可以使用多个参数调用printMax

printMax(3.0, 4.0, 5.0)

而在第二种情况下,它只接受一个参数(double数组)。

在方法体内,数字将在两种情况下作为数组进行访问。

要记住的一件事是,在第一种情况下,即使使用了varargs符号,您仍然可以传递double的单个数组。

答案 2 :(得分:1)

不完全 - double ...表示变量参数列表 - 此时传递的所有参数将作为一个数组打包在一起。

方法中只能有一个vararg参数,由于显而易见的原因,它必须是原型中的最后一个参数。然而,它将在方法中作为数组使用,因此在这种特殊情况下没有太大区别。