web-dev-qa-db-ja.com

より効率的なものは何ですか:System.arraycopyまたはArrays.copyOf?

toArrayArrayListメソッド、BlochはSystem.arraycopyおよびArrays.copyOf配列をコピーします。

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

これらの2つのコピー方法をどのように比較できますか?

71
Sawyer

違いは、Arrays.copyOfは要素をコピーするだけでなく、新しい配列も作成することです。 System.arraycopyは既存の配列にコピーします。

ご覧のとおり、Arrays.copyOfのソースは内部でSystem.arraycopyを使用して新しい配列を埋めます:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
97
Thilo

System.arraycopyはネイティブに実装されているため、1 Javaループよりも高速です。常に予想どおりの速度であるとは限りません。この例を検討してください。

Object[] foo = new Object[]{...};
String[] bar = new String[foo.length];

System.arraycopy(foo, 0, bar, 0, bar.length);

この場合、fooおよびbar配列の基本型は異なる基本型を持っているため、arraycopyの実装では、コピーするすべての参照の型を確認して確認する必要があります実際にはStringインスタンスへの参照であること。これは、配列の内容の単純なCスタイルのmemcopyよりも大幅に遅くなります。

もう1つのポイントは、Arrays.copyOfが内部でSystem.arraycopyを使用することです。そのため、System.arraycopyの面では遅くなるべきではありません2 Arrays.copyOfより。しかし、( 上記 で引用したコードから)Arrays.copyOfはリフレクションを使用して新しい配列を作成することがわかります。そのため、パフォーマンスの比較は簡単ではありません。

この分析にはいくつかの欠陥があります。

  1. 特定のバージョンのJavaの実装コードを検討しています。これらの方法は変わる可能性があり、効率に関する以前の仮定を無効にします。

  2. JITコンパイラーがこれらのメソッドの巧妙な特殊なケースの最適化を行う可能性を無視しています。そして、これは明らかにArrays.copyOfで起こります。 なぜ小さな配列でSystem.arraycopyより2倍速いArrays.copyOfなのですか? を参照してください。このメソッドは、現在の世代Java実装では「本質的」です。つまり、JITコンパイラはJavaソースコードにあるものを無視します!

しかし、どちらの方法でも、2つのバージョン間のdifferenceO(1)(つまり配列サイズに依存しない)であり、比較的小さいです。したがって、私のアドバイスは、コードを読みやすくするバージョンを使用することであり、profilingがそれを教えてくれる場合はどちらが速いかを心配することです重要です。


1-couldは高速ですが、も可能です JITコンパイラーは、ハンドコードループを最適化するのに非常に優れているため、違いはありません。

32
Stephen C

配列のexactコピーが必要な場合(たとえば、防御的なコピーを行いたい場合)、配列をコピーする最も効果的な方法は、おそらく配列オブジェクトのclone()を使用することです方法:

class C {
    private int[] arr;
    public C(int[] values){
        this.arr = values.clone();
    }
}

私はそれのパフォーマンスをテストすることを気にしませんでしたが、それはすべてネイティブであるため(呼び出しおよびコピー中のコピー)、オブジェクトをコピーする特別なJVM祝福された方法の一種であるため、かなり高速になる可能性が高くなります(そしてそれは主に他の目的のために悪)、いくつかの「ショートカット」を取ることができる可能性があります。

個人的には、他のどのコピー方法よりも遅かった場合、cloneを使用します。これは、書き込みが読みやすく、書き損じる可能性がほとんどないためです。 System.arrayCopy、 一方...

13
gustafc

System.arrayCopyははるかに高速です。 Java land。可能な限り使用してください。

12
Ry4an Brase

SunのArrays.copyOf()の実装を見ましたか?

_ public static int[] copyOf(int[] original, int newLength) {
    int[] copy = new int[newLength];
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
_

ご覧のとおり、System.arraycopy()を内部で使用しているため、パフォーマンスは同じです。

11
matsev

System.arrayCopy はネイティブに実装されているため、どのJavaコードよりも高速です。使用することをお勧めします。

3
Humphrey Bogart

議論する代わりに、これらは実際の結果です。明らかに、選択はコピーするデータの量に依存します。

byte []コピーパフォーマンステスト

10,000,000回の繰り返し40b array.copyOfRange:135ms systems.arraycopy:141ms

10,000,000回の繰り返し1000b array.copyOfRange:1861ms systems.arraycopy:2211ms

10,000,000回の繰り返し4000b array.copyOfRange:6315ms systems.arraycopy:5251ms

1,000,000回の繰り返し100,000b array.copyOfRange:15,198ms systems.arraycopy:14783ms

1
cyberthreat

System.arraycopy()のソースコードとArray.copyOf()の両方を見ると、パフォーマンスが向上します。

System.arraycopy()はCコードであり、配列上で直接動作し、値を返しません。そのため、Array.copyOf()よりもはるかに高速に動作するはずです。それにもかかわらず、新しい配列を作成する必要がある場合、またはコピー操作の値のみが必要な場合は、そのために新しい配列を作成するか、新しい配列の長さを設定するなどする必要があります。したがって、できません戻り値System.arraycopy(ソース、0、宛先、0、長さ)。

Array.copyOf()でできることは、新しい配列を作成することです。 Array.copyOf()からの戻り値を配列に割り当てるか、Array.copyOf()が目的の配列を直接操作する代わりに値を返すようにメソッドから返すことができます。したがって、コードはずっときれいに見えます。それにもかかわらず、パフォーマンスのコストのために、Array.copyOf()はジェネリック型メソッドであり、何を処理するかを事前に知りません。したがって、Array.newInstance()またはnew Object()を呼び出してから、入力の配列型にキャストする必要があります。

まとめると。パフォーマンスのためSystem.arraycopy()を使用します。よりクリーンなコードにはArray.copyOf()を使用します。

1
Kevin Ng
      class ArrayCopyDemo {
   public static void main(String[] args) {
    char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e',
            'i', 'n', 'a', 't', 'e', 'd' };
    char[] copyTo = new char[7];

    System.arraycopy(copyFrom, 2, copyTo, 0, 7);
    System.out.println(new String(copyTo));
}
 }
0
Ambika