制作一个数组的副本

时间:2011-04-26 03:57:31

标签: 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]
}

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

11 个答案:

答案 0 :(得分:522)

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

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

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

答案 1 :(得分:216)

你可以使用

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

答案 2 :(得分:167)

如果您想复制:

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

答案 3 :(得分:48)

来自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个元素,从...开始   第三个源指数到第二个目的地指数。

     

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

     

Arrays.copyOfRange():如果你想要一个数组的元素很少   复制,其中起始索引不为0,可以使用此方法进行复制   部分阵列。

答案 4 :(得分:31)

我觉得所有这些“更好的复制数组方法”并不能真正解决你的问题。

你说

  

我尝试了类似[...]的for循环,但似乎没有正常工作?

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

  • 您以某种方式将ab阵列搞砸了(例如ab引用相同的数组),或
  • 您的应用程序是多线程的,不同的线程同时读取和更新a数组。

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

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

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

答案 5 :(得分:10)

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

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

答案 6 :(得分: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();
    }
}

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

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

Apache commons你可以找到there

答案 7 :(得分: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]
}

此方法与Arrays.copyOf类似,但更灵活。两者都使用System.arraycopy

查看

答案 8 :(得分:1)

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

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

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

使用空值复制指定的数组,截断或填充(如果   必要的)所以副本有指定的长度。对于所有指数   在原始数组和副本中都有效,两个数组都会有效   包含相同的值。对于副本中有效的任何索引   但不是原始版本,副本将包含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    }

Arrays.copyOfRange()也可以解决问题:

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

将指定数组的指定范围复制到新数组中。   范围(from)的初始索引必须介于0和0之间   original.length,包括。原始[from]的值被放入   副本的初始元素(除非来自== original.length或   从==到)。原始数组中后续元素的值为   放入副本中的后续元素。最终的指数   范围(to),必须大于或等于,可以是   大于original.length,在这种情况下null放在所有   索引大于或等于的副本的元素   original.length - 来自。返回数组的长度为 -   从。生成的数组与原始数组完全相同   阵列。

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是复制数组的绝对最快的方式。

答案 9 :(得分:0)

对于数组的空安全副本,您还可以使用此answer中提供的Object.clone()方法的可选项。

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

答案 10 :(得分:0)

我对2D阵列也有类似的问题,到此结束。 我正在复制主数组并更改内部数组的值,当两个副本中的值都更改时,我感到很惊讶。基本上,两个副本都是独立的,但是包含对相同内部数组的引用,我必须对内部数组进行副本复制才能获得所需的内容。

有时称为深拷贝。相同的术语“深层复制”也可能具有完全不同的说法,并且可以说是更复杂的含义,这可能会造成混淆,尤其是对于某些无法弄清楚为什么其复制的数组无法正常工作的人而言。可能不是OP的问题,但我希望它仍然可以提供帮助。