制作一个数组的副本

bad*_*der 333 java arrays copy

我有一个a不断更新的数组.让我们说吧a = [1,2,3,4,5].我需要制作完全相同的副本a并调用它b.如果a要改变[6,7,8,9,10],b应该仍然是[1,2,3,4,5].做这个的最好方式是什么?我尝试了一个for循环:

for(int i=0; i<5; i++) {
    b[i]=a[i]
}
Run Code Online (Sandbox Code Playgroud)

但这似乎不正常.请不要使用深层复制等高级术语,因为我不知道这意味着什么.

Bal*_*a R 543

您可以尝试使用System.arraycopy()

int[] src  = new int[]{1,2,3,4,5};
int[] dest = new int[5];

System.arraycopy( src, 0, dest, 0, src.length );
Run Code Online (Sandbox Code Playgroud)

  • 令人失望的是,这里所有的讨论都是关于微观性能问题,而 99.999% 的情况下,这些问题并不重要。更重要的一点是,“src.clone()”比分配新数组并执行“arraycopy”更具可读性,并且出错的机会要少得多。(而且速度也很快。) (12认同)
  • 嘿,这对多维数组有何影响? (9认同)
  • +1不用于重新转动车轮.据我所知,这个解决方案是您在阵列复制中获得的速度更快. (7认同)
  • @FelipeHummel,@ MeBigFatGuy,@ StephenC - 这里是答案中提到的[阵列复制方法的性能测试](http://www.javapractices.com/topic/TopicAction.do?Id=3).在那个设置中,`clone()`对于250 000个元素来说是最快的. (6认同)
  • clone和arraycopy都是原生的.我希望克隆速度稍快一些.并不是说差别很重要. (5认同)
  • @Felipe,@ MeBigFatGuy - 仅适用于大型阵列.对于小型阵列,由于设置开销,复制循环可能更快.如果你查看`System.arraycopy`的javadoc,你会发现该方法需要在启动之前检查各种事物.根据静态数组类型,复制循环中不需要进行某些检查. (4认同)
  • @Adam-您应该打折那些结果。他正在使用-Xint运行代码。您不能用它来推断代码在正常运行时的性能;即启用JIT编译。 (2认同)

MeB*_*Guy 219

您可以使用

int[] a = new int[]{1,2,3,4,5};
int[] b = a.clone();
Run Code Online (Sandbox Code Playgroud)

同样.

  • 演员阵容是不必要的; 一个好的静态分析仪会警告它.但克隆绝对是制作数组新副本的最佳方法. (13认同)
  • 我只是清除OP的观点:"*如果A改为[6,7,8,9,10],B应该仍然是[1,2,3,4,5]*".OP说他尝试使用循环,但对他不起作用. (5认同)
  • @MeBigFatGuy - OP的用例需要重复复制到同一个数组,因此clone不起作用. (4认同)
  • @Stephen C,我没看过.我刚读过他想要一份副本,然后会反复更新非藏匿版本. (3认同)
  • @MeBigFatGuy - 他说*"我有一个不断更新的阵列A."*.也许我正在阅读太多内容,但我认为这意味着他也反复将A复制到B. (3认同)
  • 如果由于 findbugs 警告而采用此方法,请不要忘记检查 src 数组是否为空... (2认同)
  • 这是不正确的解决方案。一旦 b 更新,则 a 也更新 (2认同)

Evg*_*eev 174

如果你想复制一份:

int[] a = {1,2,3,4,5};
Run Code Online (Sandbox Code Playgroud)

这是要走的路:

int[] b = Arrays.copyOf(a, a.length);
Run Code Online (Sandbox Code Playgroud)

Arrays.copyOf可能比a.clone()小阵列更快.两个复制元素同样快,但clone()返回,Object因此编译器必须插入一个隐式转换int[].您可以在字节码中看到它,如下所示:

ALOAD 1
INVOKEVIRTUAL [I.clone ()Ljava/lang/Object;
CHECKCAST [I
ASTORE 2
Run Code Online (Sandbox Code Playgroud)


Kan*_*mar 54

来自http://www.journaldev.com/753/how-to-copy-arrays-in-java的很好的解释

Java阵列复制方法

Object.clone():Object类提供clone()方法,由于java中的数组也是Object,可以使用此方法实现完整的数组复制.如果您想要数组的部分副本,则此方法不适合您.

System.arraycopy():系统类arraycopy()是执行数组部分复制的最佳方法.它为您提供了一种指定要复制的元素总数以及源和目标数组索引位置的简便方法.例如,System.arraycopy(source,3,destination,2,5)将5个元素从源复制到目标,从源的第3个索引开始到目标的第2个索引.

Arrays.copyOf():如果要复制数组的前几个元素或数组的完整副本,可以使用此方法.显然它不像System.arraycopy()那样通用,但它也不会让人感到困惑和易于使用.

Arrays.copyOfRange():如果要复制数组的少数元素,其中起始索引不为0,则可以使用此方法复制部分数组.


Ste*_*n C 32

我觉得所有这些"复制数组的更好方法"并不能解决你的问题.

你说

我试过像[...]这样的for循环,但似乎没有正常工作?

看看那个循环,没有明显的理由让它不起作用......除非:

  • 你以某种方式具有ab阵列弄乱了(例如ab指代相同的阵列),或
  • 你的应用程序是多线程的,不同的线程同时读取和更新a数组.

在任何一种情况下,进行复制的替代方法都无法解决潜在的问题.

第一种情况的修复是显而易见的.对于第二种情况,您必须找出一些同步线程的方法.原子数组类没有帮助,因为它们没有原子复制构造函数或克隆方法,但使用原始互斥体进行同步将起到作用.

(你的问题中有一些提示让我认为这确实与线程有关;例如你的陈述a不断变化.)


小智 14

您可以尝试在Java中使用Arrays.copyOf()

int[] a = new int[5]{1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
Run Code Online (Sandbox Code Playgroud)

  • 冗余:/sf/answers/1117406461/ 说了同样的话。 (3认同)

Che*_*rry 7

从数组中调用长度的所有解决方案,添加代码冗余null checkersconsider示例:

int[] a = {1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();

//What if array a comes as local parameter? You need to use null check:

public void someMethod(int[] a) {
    if (a!=null) {
        int[] b = Arrays.copyOf(a, a.length);
        int[] c = a.clone();
    }
}
Run Code Online (Sandbox Code Playgroud)

我建议您不要发明轮子并使用实用程序类,其中已经执行了所有必要的检查.考虑来自apache commons的ArrayUtils.您的代码变得更短:

public void someMethod(int[] a) {
    int[] b = ArrayUtils.clone(a);
}
Run Code Online (Sandbox Code Playgroud)

您可以在那里找到Apache公共资源


ROM*_*eer 7

你也可以使用Arrays.copyOfRange.

示例:

public static void main(String[] args) {
    int[] a = {1,2,3};
    int[] b = Arrays.copyOfRange(a, 0, a.length);
    a[0] = 5;
    System.out.println(Arrays.toString(a)); // [5,2,3]
    System.out.println(Arrays.toString(b)); // [1,2,3]
}
Run Code Online (Sandbox Code Playgroud)

这种方法类似Arrays.copyOf,但更灵活.它们都System.arraycopy在引擎盖下使用.

: