Java Varargs方法修改调用者';是数组而不是它自己的副本?

Java Varargs方法修改调用者';是数组而不是它自己的副本?,java,variadic-functions,Java,Variadic Functions,我有一个简单的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 {

我有一个简单的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
之前克隆对象数组(因此不同的对象标识符):


那么
A
中的
f
如何修改调用者的数组而不是它自己的副本呢?

最后,数组是一个对象,所以你不修改数组引用本身,而是修改它允许的内容。

看起来你在这里欺骗了自己:

Object os = new Object[]{1,2,3};
System.out.println(os);
f(os);
由于
os
被键入为
Object
,因此它被解释为varargs数组的第一个元素。传递到方法中的实际上是一个新的
对象[]
,它的单个元素是您的
对象[]

如果执行以下操作,它将打印相同的实例:

Object[] os = new Object[]{1,2,3};
System.out.println(os);
f(os);
f
方法需要制作数组本身的防御副本,以确保调用方传入的数组不会被修改。正如arshajii所指出的,varargs是最重要的数组参数,当给定参数列表时,它具有创建新数组的“额外”行为

无论如何,您可以使用创建副本,该副本将委托给(不太安全的类型)。

varargs是一种数组类型,但是如果元素作为参数单独传递,则可以使用语法糖允许动态创建数组

也就是说,这两个签名是相同的:

static long f(long... xs) {
static long f(long[] xs) {
除了可以使用单独的元素而不是数组来调用varargs之外

当然,如果您绕过动态创建并自己创建一个要传入的数组,那么该数组将被修改

那么,f在A中是如何修改调用方的数组而不是它自己的副本的呢


它没有自己的副本。它有一个调用方数组的引用。

+1很好。值得一提的是,varargs方法与接受数组参数的等效方法完全相同,只是当您向varargs方法传递多个参数时,会为您创建一个数组。Java按值复制引用。它从不将对象或数组复制或克隆为参数(或任何其他情况),除非您显式地这样做。是的,但他修改了不同数组的内容。这些是原语,没有引用。@f1sh OP正在修改方法中的数组值,因此在数组中调用它后,它的内容将被修改。
static long f(long... xs) {
static long f(long[] xs) {