复制一个数组

我有一个不断更新的数组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];
}

但这似乎并不正确。请不要使用像深度复制等高级术语,因为我不知道那是什么意思。

792710 次浏览

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

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


System.arraycopy( src, 0, dest, 0, src.length );

但是,在大多数情况下使用clone()可能更好:

int[] src = ...
int[] dest = src.clone();

你可以使用

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

我有一种感觉,所有这些“复制数组的更好方法”都不能真正解决您的问题。

你说

我尝试了一个for循环,像[…]但它似乎不能正常工作?

看看这个循环,有没有明显的原因让它不能工作…除非:

  • 你以某种方式把ab数组弄乱了(例如,ab指的是同一个数组),或者
  • 你的应用程序是多线程的,不同的线程同时读取和更新a数组。

在任何一种情况下,复制的其他方法都不能解决潜在的问题。

解决第一种情况的办法是显而易见的。对于第二种场景,您必须找到同步线程的方法。原子数组类没有帮助,因为它们没有原子复制构造函数或克隆方法,但是使用原语互斥量进行同步就可以了。

(你的问题中有一些暗示让我认为这确实与线程有关;例如,你说a是不断变化的。)

如果你想复制下列文件:

int[] a = {1,2,3,4,5};

这是一条正确的道路:

int[] b = Arrays.copyOf(a, a.length);

在小型数组上,Arrays.copyOf可能比a.clone()快。两者复制元素的速度相同,但clone()返回Object,因此编译器必须插入隐式转换到int[]。你可以在字节码中看到它,就像这样:

ALOAD 1
INVOKEVIRTUAL [I.clone ()Ljava/lang/Object;
CHECKCAST [I
ASTORE 2

所有的解决方案,调用长度从数组,添加你的代码冗余空检查器考虑的例子:

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();
}
}

我建议您不要白费力气,而是使用已经执行了所有必要检查的实用程序类。考虑一下apache commons中的ArrayUtils。你的代码变得更短:

public void someMethod(int[] a) {
int[] b = ArrayUtils.clone(a);
}

你可以找到在那里

你也可以使用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]
}

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

看到:

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

Java数组拷贝方法

Object.clone ():对象类提供clone()方法和since数组 在java中也是一个对象,可以用这个方法来实现完全 数组副本。如果你想要部分拷贝,这种方法不适合你 数组。< / p > 系统类arraycopy()是最好的方法 数组的部分副本。它提供了一种简单的方法来指定 要复制的元素总数以及源和目标数组 索引位置。例如System。Arraycopy (source, 3, destination, 将从源复制5个元素到目标,从 源的第三个索引到目的的第二个索引

Arrays.copyOf ():如果你想复制数组的前几个元素或 完整复制数组,可以使用此方法。显然不是这样的 像System.arraycopy()一样通用,但也不容易混淆 使用。< / p >

Arrays.copyOfRange ():如果你想要数组中的少数元素为 已复制,其中起始索引不为0,您可以使用此方法进行复制 局部数组。< / p >

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

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

对于数组的空安全副本,也可以使用可选的Object.clone()方法。

int[] arrayToCopy = {1, 2, 3};
int[] copiedArray = Optional.ofNullable(arrayToCopy).map(int[]::clone).orElse(null);

如果你必须使用原始数组而不是ArrayList,那么Arrays可以满足你的需要。如果查看源代码,这些绝对是获取数组副本的最佳方法。它们确实有一些很好的防御性编程,因为如果你给System.arraycopy()方法提供不合逻辑的参数,它会抛出大量未经检查的异常。

你可以使用Arrays.copyOf(),它将从第一个到Nth的元素复制到新的更短的数组。

public static <T> T[] copyOf(T[] original, int newLength)

复制指定的数组,截断或填充null(如果 必须),因此副本具有指定的长度。对于所有 在原始数组和副本中都有效,两个数组会吗 包含相同的值。用于副本中有效的任何索引 但不是原始文件,副本将包含null。这样的指数将 类的指定长度大于时才存在 原始数组中。结果数组的类与 原始数组。

2770
2771    public static <T,U> T[] More ...copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
2772        T[] copy = ((Object)newType == (Object)Object[].class)
2773            ? (T[]) new Object[newLength]
2774            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
2775        System.arraycopy(original, 0, copy, 0,
2776                         Math.min(original.length, newLength));
2777        return copy;
2778    }

or Arrays.copyOfRange()也可以做到:

public static <T> T[] copyOfRange(T[] original, int from, int to)

拷贝指定数组的指定范围到一个新数组。 范围(from)的初始索引必须在0和之间 原创。长度,包容。在original[from]处的值被放入 复制的初始元素(除非from == original。长度或 从==到)。原始数组中后续元素的值为 放在副本中的后续元素中。的最终索引 Range (to)必须大于或等于from,可以为 比原来更大。长度,在这种情况下,null被放置在all中 副本中索引大于或等于的元素 原创。长度-从。返回数组的长度为- 从。生成的数组与原始数组的类完全相同 数组。< / p >

3035    public static <T,U> T[] More ...copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
3036        int newLength = to - from;
3037        if (newLength < 0)
3038            throw new IllegalArgumentException(from + " > " + to);
3039        T[] copy = ((Object)newType == (Object)Object[].class)
3040            ? (T[]) new Object[newLength]
3041            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
3042        System.arraycopy(original, from, copy, 0,
3043                         Math.min(original.length - from, newLength));
3044        return copy;
3045    }

正如你所看到的,这两个都是System.arraycopy上的包装器函数,具有防御逻辑,即你试图做的是有效的。

System.arraycopy绝对是复制数组的最快方法。

我在2D数组中遇到了类似的问题,并在这里结束。 我复制了主数组并更改了内部数组的值,当两个副本中的值都发生变化时,我感到惊讶。基本上这两个副本都是独立的,但包含对相同内部数组的引用,我必须对内部数组制作一个数组的副本才能得到我想要的

这有时被称为深度复制。同样的术语“深度抄袭”;也可以有完全不同的、可以说是更复杂的含义,这可能会令人困惑,特别是对于那些不明白为什么复制的数组没有按照应有的方式运行的人来说。这可能不是OP的问题,但我希望它仍然能有所帮助。