我有这个简单的varargs方法,它将列表中的每个项目分开:
import java.util.*;
class A {
static long f(long... xs) {
Arrays.sort(xs);
long y = 100000000;
for (int i = xs.length - 1; i >= 0; i--)
y /= xs[i];
return y;
}
static {
System.out.println(f(5,2,6,3,9,3,13,4,5));
long[] xs = new long[]{5,2,6,3,9,3,13,4,5};
System.out.println(Arrays.toString(xs));
System.out.println(f(xs));
System.out.println(Arrays.toString(xs));
}
}
我希望它传递数组的副本,但显然它以某种方式修改我传入的数组,而不是它自己的本地副本:
$ javac A.java && java A
79
[5, 2, 6, 3, 9, 3, 13, 4, 5]
79
[2, 3, 3, 4, 5, 5, 6, 9, 13]
所以我写了这个简单的测试程序:
class B {
static void f(Object... os) {
System.out.println(os);
}
static {
Object os = new Object[]{1,2,3};
System.out.println(os);
f(os);
}
}
它符合我的预期,它会在将对象数组传递给f
之前克隆它(因此不同的对象标识符):
$ javac B.java && java B
[Ljava.lang.Object;@1242719c
[Ljava.lang.Object;@4830c221
那么f
A
如何修改调用者的数组而不是自己的副本呢?
答案 0 :(得分:15)
看起来你已经欺骗了自己:
Object os = new Object[]{1,2,3};
System.out.println(os);
f(os);
由于os
的类型为Object
,因此它被解释为varargs数组的第一个元素。传递给该方法的内容实际上是一个新的Object[]
,其单个元素是您的Object[]
。
如果您执行以下操作,它将打印相同的实例:
Object[] os = new Object[]{1,2,3};
System.out.println(os);
f(os);
f
方法需要制作数组本身的防御副本,以保证调用者传入的数组不被修改。正如arshajii所指出的,varargs是最重要的数组参数,在给定参数列表时创建新数组的“奖励”行为。
无论如何,您可以使用Arrays.copyOf
制作副本,该副本代表(类型安全性较低)System.arraycopy
。
答案 1 :(得分:3)
varargs 是一种数组类型,但是如果元素作为参数单独传递,则使用语法糖来允许动态数组创建。
也就是说,这两个签名是相同的:
static long f(long... xs) {
static long f(long[] xs) {
除了可以使用单独的元素而不是数组调用varargs
当然,如果你绕过动态创建并自己创建一个数组来传入数组,那么数组将被修改。
答案 2 :(得分:1)
那么如何修改调用者的数组而不是自己的副本?
它没有自己的副本。它有一个对调用者数组的引用。
答案 3 :(得分:-1)
最后,数组是一个对象,因此您不要修改数组引用本身而不是其允许的内容。