編集2:以下は、System.arraycopyを使用して多次元配列のクローン作成の制限を回避する方法を示すDuffyMoの応答に基づくコードスニペットです。
import Java.util.Arrays;
public class Randar {
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}};
private static int[][] arrayChanges = new int[arrayMaster.length][2];
public Randar () {
}
public static void main(String[] args) {
arrayChanges[0][0] = 0;
resetArrays(arrayChanges, arrayMaster);
arrayChanges[0][0] = 0;
System.out.format("arrayMaster: %s, arrayChanges: %s", Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges));
}
public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) {
for (int a=0; a< arrayMaster.length; a++) {
System.arraycopy(arrayMaster[a], 0, arrayChanges[a], 0, arrayMaster[a].length);
}
// arrayChanges = arrayMaster.clone(); will NOT work as expected
}
}
[元の質問] Javaで多次元配列を(完全に)複製する簡単な方法は何ですか?このプログラムは私の問題を説明しています。
import Java.util.Arrays;
public class Randar {
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}};
static private int[][] arrayChanges = arrayMaster;
public static void main(String[] args) {
arrayChanges[0][0] = 0;
resetArrays();
System.out.format("arrayMaster: %s, arrayChanges: %s",Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges));
}
public static void resetArrays() {
arrayChanges = arrayMaster.clone();
}
}
上記のコードを実行すると、私の意図に反して、arrayMasterがarrayChangesと同様に変更されます。 arrayMasterの各1次元配列メンバーのクローンを作成できると考えて、次の問題を回避しようとしました。
for (int iter = 0; iter < arrayMaster.length; iter++) {
arrayChanges[iter] = arrayMaster[iter].clone();
}
しかし、何らかの理由でNullPointerExceptionを与えるコードを実行すると。配列の個々の整数値をループするメソッドを書くことは私の唯一の選択肢ですか?
ありがとう。
編集1:これも問題を解決しません。
import Java.util.Arrays;
public class Randar {
public int[][] arrayMaster = {{6,1}, {10,1}, {1,1}};
private int[][] arrayChanges = arrayMaster.clone();
public Randar () {
}
public static void main(String[] args) {
Randar Randar1 = new Randar();
Randar1.arrayChanges[0][0] = 0;
resetArrays(Randar1.arrayChanges, Randar1.arrayMaster);
Randar1.arrayChanges[0][0] = 0;
System.out.format("arrayMaster: %s, arrayChanges: %s", Arrays.deepToString(Randar1.arrayMaster), Arrays.deepToString(Randar1.arrayChanges));
}
public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) {
/*for (int a=0; a< arrayMaster.length; a++) {
System.arraycopy(arrayMaster[a].clone(), 0, arrayChanges[a], 0, arrayMaster[a].length);
} */
arrayChanges = arrayMaster.clone();
}
}
上記のコードを実行すると、私の意図に反して、arrayMasterがarrayChangesと同様に変更されます。
この線
static private int[][] arrayChanges = arrayMaster;
犯人です。この行により、arrayChanges
とarrayMaster
が同じオブジェクトを指すようになるため、どちらかからオブジェクトにアクセスすると、どちらかへの変更が表示されます。
編集:多次元配列の1つの次元を複製するとどうなりますか
Eric Lippertが説明 のように、配列は概念的には変数のリストです。 static private int[][] arrayChanges = arrayMaster;
の同じ配列を指すように別の変数を割り当てるだけの場合は、変数のセットをまったく変更していません。 arrayChanges
以外の新しい変数を作成していないため、オペレーティングシステム/ JVMからメモリを取得していないため、arrayMaster
に加えた変更はすべてarrayChanges
およびその逆。
次に、2次元配列を見てみましょう。 Javaでは、2次元配列は、これらの変数のそれぞれが1次元配列を参照するというプロパティを持つ変数のリストです。したがって、2次元配列のクローンを作成するたびに、変数の新しいリストを作成します。各リストは、古い変数が指しているのと同じ場所を指します。したがって、arrayChanges[0] = new int[10]
を安全に記述できるという点で少し得られています。 arrayMaster
に影響を与えることはありませんが、arrayChanges[i][j]
の参照を開始するとすぐに、arrayMaster
が参照するのと同じ第2レベルの配列を参照します。 intの2次元配列をディープコピーするために本当に必要なのは
public static int[][] deepCopyIntMatrix(int[][] input) {
if (input == null)
return null;
int[][] result = new int[input.length][];
for (int r = 0; r < input.length; r++) {
result[r] = input[r].clone();
}
return result;
}
将来この答えを見るかもしれない人へ:はい、ここでint
をT
に置き換えてメソッドをジェネリックにする方が良いですが、この目的のために、より具体的なディープコピーメソッドはより簡単ですよく説明します。
clone
は「浅い」コピーを行います。つまり、最も外側の配列は複製されますが、そこに格納されている値は変更されません。したがって、A1 = {B1、B2、B3}があり、それをA2に複製すると、A2の初期コンテンツは{B1、B2、B3}になります。 A1を{C1、B2、B3}に変更すると、A2は変更されませんが、B1の内容を(置き換えずに)変更すると、A2はその変更を「認識」します。
目的を達成するには、外部配列とその外部配列の要素(内部配列)をclone
ループする必要があります。
ピジンJava:
int[][] A2 = A1.clone();
for (int i = 0; i < A2.length; i++) {
A2[i] = A2[i].clone();
}