forms参数类型声明中double …和double 之间的区别
我有疑问:这两个声明有什么区别?
public static void printMax(double... numbers) { ... } public static void printmax(double numbers[]) { ... }
是double... numbers
与double numbers[]
相同?
关于varargs
方法参数声明中的Type...
构造通常称为varargs。 在JLS中,它被称为变量arity参数。
JLS 8.4.1格式参数
列表中的最后一个forms参数是特殊的; 它可以是一个可变的arity参数,由类型后面的省略号表示。
如果最后一个forms参数是类型为
T
的变量arity参数,则认为它定义了类型为T[]
的forms参数。 然后该方法是可变的arity方法。 否则,它是一种固定的arity方法。 变量arity方法的调用可能包含比forms参数更多的实际参数表达式。 将评估与变量arity参数之前的forms参数不对应的所有实际参数表达式,并将结果存储到将传递给方法调用的数组中。
为了在代码中说明,这是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...
实际上是T[]
。 也就是说,即使使用varargs,您仍然可以执行以下操作:
f(new int[] { 1, 2, 3 }); // prints "1", "2", "3"
在这里,您手动创建数组以保存vararg参数。 事实上,如果你去反编译代码,你会发现就像JLS指定的那样, f
确实采用了int[]
参数,而f(1, 2, 3)
实现为f(new int[] { 1, 2, 3 })
。
也可以看看
- Java语言指南/ varargs
Varargs陷入困境
如何解决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!!!
由于varargs的解析方式,最后一个语句使用objs.length
objs = null
调用,这当然会导致objs.length
NullPointerException
。 如果要为varargs参数提供一个null
参数,可以执行以下任一操作:
count(new Object[] { null }); // prints "1" count((Object) null); // prints "1"
相关问题
以下是人们在处理varargs时提出的一些问题的示例:
- varargs和重载的错误?
- 如何使用varargs和reflection
- 具有固定/可变arity(varargs)匹配的最具体方法
何时使用varargs
如前一节所示,varargs可能很棘手。 但是,在适当的情况下使用它们可以产生更简洁的代码。
以下是Effective Java 2nd Edition的引用,第42项:明智地使用varargs (作者强调):
教训很清楚。 不要改进每个具有最终数组参数的方法; 仅当调用真正对可变长度值序列进行操作时才使用varargs 。
varargs不仅容易混淆,而且成本也很高。 有效的Java第二版实际上建议为最常见的使用场景提供固定的重载。
假设您已确定95%的方法调用具有三个或更少的参数。 然后声明方法的五个过载,每个过载一个零到三个普通参数,并且当参数数量超过三个时使用单个变量。
这本书的深度更深入,但基本上你应该只在实际有意义的时候使用varargs。 即使在这些情况下,出于性能原因,您仍可能需要考虑提供固定过载。
相关问题
- Java的varargs性能。
API链接
以下是varargs有意义的一些示例:
-
java.util.Arrays.asList(T...)
-
java.util.PrintStream.printf(String format, Object... args)
-
java.lang.reflect.Method.invoke(Object obj, Object... args)
关于数组声明
拜托,请不要养成这样声明数组的习惯:
int x[];
您应该使用类型而不是标识符来放置括号:
int[] x;
请注意,这也是上述讨论中引用数组的方式,例如T[]
int[]
等。
相关问题
-
Object[] x
和Object x[]
之间有什么区别吗? - Java中的
int[] myArray
和int myArray[]
之间的区别 - 在数组声明
int[] k,i
和int k[],i
- 这些声明导致
i
类型不同!
- 这些声明导致
主要区别在于,在第一种情况下,您可以使用多个参数调用printMax
:
printMax(3.0, 4.0, 5.0)
而在第二种情况下,它只接受一个参数(一个double
数组)。
在方法体内,在两种情况下都将数字作为数组进行访问。
要记住的一件事是,在第一种情况下,即使使用了varargs表示法,您仍然可以传递单个double
数组。
不完全 – double …表示变量参数列表 – 此时传递的所有参数将作为一个数组打包在一起。
方法中只能有一个vararg参数,由于显而易见的原因,它必须是原型中的最后一个参数。 然而,它将在方法中作为数组使用,因此在这种特定情况下没有太大区别。