私は常に更新されている配列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]
}
しかし、それは正しく機能していないようです。ディープコピーなどの高度な用語は使用しないでください。これがどういう意味かわかりません。
System.arraycopy() を使用して試すことができます。
int[] src = new int[]{1,2,3,4,5};
int[] dest = new int[5];
System.arraycopy( src, 0, dest, 0, src.length );
あなたが使用することができます
int[] a = new int[]{1,2,3,4,5};
int[] b = a.clone();
同様に。
コピーを作成する場合は、
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
/からの良い説明 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) は、sourceの3番目のインデックスからdestinationの2番目のインデックスまで、5つの要素をsourceからdestinationへコピーします。
Arrays.copyOf(): 配列の最初のいくつかの要素または配列のフルコピーをコピーする場合は、このメソッドを使用できます。明らかにSystem.arraycopy()のように汎用性はありませんが、混乱を招くこともなく使いやすいこともありません。
Arrays.copyOfRange() :開始インデックスが0ではない配列の要素をいくつかコピーしたい場合は、このメソッドを使用して部分配列をコピーできます。
これらの「配列をコピーするためのより良い方法」すべてが実際にあなたの問題を解決するわけではないと私は感じています。
あなたは言う
[...]のようなforループを試しましたが、それは正しく動作していないようですか?
そのループを見ると、 明白な理由はありません それが機能しないためです...
a
とb
の配列が混乱している(例えばa
とb
が同じ配列を参照している)場合、またはa
配列を読み込んで更新しています。どちらの場合でも、コピーを実行するための別の方法では根本的な問題は解決されません。
最初のシナリオの修正は明らかです。 2番目のシナリオでは、スレッドを同期させる方法を考え出す必要があります。アトミックコピーコンストラクタやクローンメソッドがないため、アトミック配列クラスは役に立ちませんが、プリミティブミューテックスを使用して同期するとうまくいきます。
(あなたの質問には、これが本当にスレッドに関連していると思うように私に導くヒントがあります。例えば、a
は絶えず変化しているというあなたのステートメント。)
JavaでArrays.copyOf()を使ってみることができます。
int[] a = new int[5]{1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
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
を使用しています。
:を参照
配列から長さを呼び出すすべての解決策は、あなたのコードを追加します。
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コモンズあなたが見つけることができます そこ
ArrayList
ではなく生の配列を操作しなければならない場合は、Arrays
に必要なものがあります。ソースコードを見れば、これらは配列のコピーを取得するための絶対的に最良の方法です。 System.arraycopy()
メソッドは、論理的でないパラメータを指定すると、多くの未チェックの例外をスローするので、それらにはかなりの防御的プログラミングがあります。
最初の要素からNth
要素までを新しい短い配列にコピーする Arrays.copyOf()
を使用できます。
public static <T> T[] copyOf(T[] original, int newLength)
コピーが指定された長さになるように、指定された配列をコピーし、切り捨てるか(必要に応じて)NULLで埋めます。元の配列とコピーの両方で有効なすべてのインデックスに対して、2つの配列は同じ値を含みます。コピーでは有効だが元のインデックスではないインデックスの場合、コピーには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からoriginal.lengthまでの間になければなりません。 original [from]の値がコピーの最初の要素に配置されます(from == original.lengthまたはfrom == toを除く)。元の配列内の後続の要素からの値は、コピー内の後続の要素に配置されます。 from(以上)でなければならない範囲(to)の最後のインデックスは、original.lengthより大きくすることができます。この場合、インデックスがoriginal以上のコピーのすべての要素にnullが配置されます。長さ - から。返される配列の長さはto-fromになります。結果の配列は、元の配列とまったく同じクラスです。
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
は配列をコピーするための絶対的な最速の方法です。
配列のnullセーフコピーの場合は、this answer で提供されているObject.clone()
メソッドと共にオプションを使用することもできます。
int[] arrayToCopy = {1, 2, 3};
int[] copiedArray = Optional.ofNullable(arrayToCopy).map(int[]::clone).orElse(null);