如何在Java中复制一个二维数组?

62

我需要在我正在开发的项目中复制一个相当大的二维数组。我有两个二维数组:

int[][]current;
int[][]old;

我还有两种方法可以进行复制。我需要复制这个数组,因为当前它经常被更新。

public void old(){
  old=current
}

并且

public void keepold(){
  current=old
}

然而,这并不起作用。如果我调用old,对current进行更新,然后调用keepold,那么当前的值将不等于最初的值。为什么会这样呢?

谢谢。


1
当你发现需要复制多维数组时,你可能会发现是时候考虑创建一个新类来更好地管理这些数据了。 - corsiKa
你知道如何在Java中复制一维数组吗? - jmg
1
可以将问题声明为作业问题。但标签是用于分类的,而“作业”不是一个好的分类器,我个人认为。 - Louis Rhys
13个回答

72

自 Java 8 起,可以使用 Streams API:

int[][] copy = Arrays.stream(matrix).map(int[]::clone).toArray(int[][]::new);

2
很好。真的很好。 - GhostCat
这个答案比其他答案更快吗? - mbomb007
可能,流式API已经高度优化,并且toArray方法中的初始化也是如此。预设数组很少是一个好选择。 - Benjamin Marwell
3
IntelliJ对于方法引用有很多话可说。这是一个非常好的解决方案! Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); - ThetaSinner
为什么在这里我们不需要指定数组大小,例如int[3][3] :: new? - stewchicken
因为您将方法引用传递给了二维整型数组 int[][]::new 的构造函数,以便在 toArray 收集器中使用。收集器将调用提供的方法引用,即构造函数,并为您提供适当的维度参数。 - Björn Zurmaar

48

current=oldold=current会使这两个数组引用同一个对象,因此如果你随后修改了currentold也会被修改。要将一个数组的内容复制到另一个数组,请使用for循环。

for(int i=0; i<old.length; i++)
  for(int j=0; j<old[i].length; j++)
    old[i][j]=current[i][j];

顺便提一下: 对于一个一维数组,你可以使用Arrays.copyOf来避免创建自己的for循环。


1
谢谢!Arrays.deepEquals(current, old)同样有效吗? - badcoder
不,Arrays.deepEquals是比较两个数组的内容是否相同,如果相同则返回true。Arrays.copyOf同样适用于一维数组。 - Louis Rhys
13
你不应该将“old”指定给“current”,而是应该反过来。 - goonerify

26
/**
 * Clones the provided array
 * 
 * @param src
 * @return a new clone of the provided array
 */
public static int[][] cloneArray(int[][] src) {
    int length = src.length;
    int[][] target = new int[length][src[0].length];
    for (int i = 0; i < length; i++) {
        System.arraycopy(src[i], 0, target[i], 0, src[i].length);
    }
    return target;
}

能否修改此代码以支持对象的n维数组

需要支持任意长度的数组,并检查源和目标是否具有相同的维度,你还需要递归复制每个数组的每个元素,以防该对象也是一个数组。

我发表这篇文章已经有一段时间了,但我找到了一个 好的示例 来创建一个n维数组类的方法。该类在构造函数中接受零个或多个整数,指定每个维度的大小。该类使用底层的平坦数组Object []并使用维度和乘法器数组来计算每个元素的索引。(这是C编程语言中数组的实现方式)

复制NDimensionalArray实例就像复制其他2D数组一样容易,但你需要确保每个NDimensionalArray对象具有相等的维度。这可能是最简单的方法,因为没有递归,这使表示和访问更简单。


12

我写了一个简单的函数,使用System.arraycopy来复制多维int数组,最终解决了它。

public static void arrayCopy(int[][] aSource, int[][] aDestination) {
    for (int i = 0; i < aSource.length; i++) {
        System.arraycopy(aSource[i], 0, aDestination[i], 0, aSource[i].length);
    }
}

或者实际上我为我的用例进行了改进:

/**
 * Clones the provided array
 * 
 * @param src
 * @return a new clone of the provided array
 */
public static int[][] cloneArray(int[][] src) {
    int length = src.length;
    int[][] target = new int[length][src[0].length];
    for (int i = 0; i < length; i++) {
        System.arraycopy(src[i], 0, target[i], 0, src[i].length);
    }
    return target;
}

6
您可以按照以下步骤进行操作:
public static int[][] copy(int[][] src) {
    int[][] dst = new int[src.length][];
    for (int i = 0; i < src.length; i++) {
        dst[i] = Arrays.copyOf(src[i], src[i].length);
    }
    return dst;
}

2

使用Java 8,可以通过以下方式实现:

最初的回答:

int[][] destination=Arrays.stream(source)
                    .map(a ->  Arrays.copyOf(a, a.length))
                    .toArray(int[][]::new);

为什么这里我们不需要指定数组大小,比如 int[3][3]::new? - stewchicken

1

Java中的数组是对象,所有对象都是按引用传递的。为了真正“复制”一个数组,而不是为数组创建另一个名称,您必须创建一个新数组并复制所有值。请注意,System.arrayCopy将完全复制1维数组,但不会复制2维数组。原因是2D数组实际上是1D数组的1D数组,并且arrayCopy复制指向相同内部1D数组的指针。


1
数组不是对象。数组变量是引用,类似于对象变量是引用,但它们不是对象。 - Andrew Case
数组是对象。Java语言规范第10章。在Java编程语言中,数组是对象(§4.3.1),动态创建,并且可以分配给类型为Object的变量(§4.3.2)。类Object的所有方法都可以在数组上调用。https://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html#:~:text=In%20the%20Java%20programming%20language,be%20invoked%20on%20an%20array. - aran

0

我正在使用这个函数:

public static int[][] copy(final int[][] array) {
    if (array != null) {
        final int[][] copy = new int[array.length][];

        for (int i = 0; i < array.length; i++) {
            final int[] row = array[i];

            copy[i] = new int[row.length];
            System.arraycopy(row, 0, copy[i], 0, row.length);
        }

        return copy;
    }

    return null;
}

这种方法的巨大优势在于它可以复制行数不同的数组,比如:
final int[][] array = new int[][] { { 5, 3, 6 }, { 1 } };

0

以下是如何使用循环完成它的方法。

public static int[][] makeCopy(int[][] array){
    b=new int[array.length][];

    for(int row=0; row<array.length; ++row){
        b[row]=new int[array[row].length];
        for(int col=0; col<b[row].length; ++col){
            b[row][col]=array[row][col];
        }
    }
    return b;
}

请注意,这种方法比基于System.arraycopy的解决方案慢得多。System.arraycopy是基于底层硬件平台本地实现的。 - Michael

0

你也可以使用 for each 循环

int r=0;
for(int[] array:old){
    int c=0;
    for(int element:array)
        current[r][c++]=array;
    r++;
}

或者

int c=0;
for(int array[]:old){
    System.arraycopy(array,0,current[c++],0,array.length);
}

然而像这样:

int c=0;
for(int[] array:old){
    current[c++]=array;
}

这样做是错误的,因为它只会复制旧子数组的引用,对旧数组所做的更改将反映在当前数组中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接