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

标签 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 {
        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

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

最佳答案

看起来你在这里自欺欺人:

Object os = new Object[]{1,2,3};
System.out.println(os);
f(os);

由于 os 被键入为 Object,它被解释为可变参数数组的第一个元素。传入该方法的实际上是一个新的 Object[],其单个元素是您的 Object[]

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

Object[] os = new Object[]{1,2,3};
System.out.println(os);
f(os);

f 方法需要对数组本身进行防御性复制,以保证调用者传入的数组不被修改。正如 arshajii 指出的那样,可变参数是最重要的数组参数,具有在给定参数列表时创建新数组的“奖励”行为。

无论如何你可以使用Arrays.copyOf制作副本,委托(delegate)给(类型安全性较低的)System.arraycopy .

关于java - Varargs 方法修改调用者的数组而不是它自己的副本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17728425/

相关文章:

java - 带有空格的长度的正则表达式

c - 在没有 stdarg 的情况下访问可变参数函数参数

java - 确切的重载解决程序 - 为什么 f(1) 调用 f(int...arg) 和 f(long...arg) 没有歧义?

java - 将 GWT 从 2.8.1 升级到 2.8.2 后出现 "XmlRootElement cannot be resolved to a type"错误

java - Java注解成员可以使用哪些类型?

java - Grizzly JAX-RS 未返回 400 错误请求

c# - DDD - 实体状态转换

c - va_arg 返回值警告的标准 C 转换

function - PowerShell 传递函数中接收到的所有参数,并处理带空格的参数

c++ - C/C++ va_arg - 有没有办法跳过一个参数?