webentwicklung-frage-antwort-db.com.de

Was ist effizienter: System.arraycopy oder Arrays.copyOf?

Die toArray-Methode in ArrayList, Bloch verwendet sowohl System.arraycopy als auch Arrays.copyOf, um ein Array zu kopieren.

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;
}

Wie kann ich diese beiden Kopiermethoden vergleichen und wann sollte ich welche verwenden?

70
Sawyer

Der Unterschied ist, dass Arrays.copyOf nicht nur Elemente kopiert, sondern auch ein neues Array erstellt. System.arrayCopy kopiert in ein vorhandenes Array.

Hier ist die Quelle für Arrays.copyOf, da Sie System.arraycopy intern verwenden können, um das neue Array aufzufüllen.

  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;
}
95
Thilo

Während System.arraycopy nativ implementiert ist, könnte es sein1 Sie ist schneller als eine Java-Schleife und ist nicht immer so schnell, wie Sie vielleicht erwarten. Betrachten Sie dieses Beispiel:

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

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

In diesem Fall haben die Basistypen der Arrays foo und bar unterschiedliche Basistypen. Daher muss die Implementierung von arraycopy den Typ jeder kopierten Referenz überprüfen, um sicherzustellen, dass es sich tatsächlich um eine Referenz auf eine String-Instanz handelt. Das ist wesentlich langsamer als eine einfache Memcopie des Arrays im C-Stil.

Der andere Punkt ist, dass Arrays.copyOfSystem.arraycopy unter der Haube verwendet, so dass die Einsparung durch Erstellen eines neuen Arrays und das eigene Ausfüllen mit arraycopy minimal wäre. Angenommen, das ist es, was Sie versuchen zu tun ...

Mein Rat wäre, die Version zu verwenden, die den Code am besten lesbar macht, und sich nur Gedanken darüber zu machen, welche schneller ist, wenn Profiling Ihnen sagt, dass es wichtig ist.


1 - Es ist könnte schneller sein, aber es ist auch möglich, dass der JIT-Compiler so gut arbeitet, eine Handcodeschleife zu optimieren, dass es keinen Unterschied gibt.

31
Stephen C

Wenn Sie eine genaue Kopie eines Arrays benötigen (beispielsweise, wenn Sie eine defensive Kopie erstellen möchten), ist die effektivste Methode zum Kopieren eines Arrays wahrscheinlich die Methode clone() des Array-Objekts:

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

Ich habe mich nicht die Mühe gemacht, die Leistung davon zu testen, aber es bietet eine gute Chance, ziemlich schnell zu sein, da alles nativ ist (Zuweisung und Kopieren in Aufruf), und das Klonen eine Art von JVM-gesegneter Art ist, Objekte zu kopieren (und zwar meistens böse für andere Zwecke) und wahrscheinlich einige "Abkürzungen" nehmen können.

Persönlich würde ich immer noch clone verwenden, wenn es langsamer wäre als jede andere Art des Kopierens, weil es einfacher zu lesen ist und beim Schreiben fast unmöglich ist. System.arrayCopy, andererseits ...

13
gustafc

System.arrayCopy ist viel schneller. Es befindet sich im System, da es eine direkte Speicherkopie außerhalb von Java verwendet. Verwenden Sie es wenn möglich.

12
Ry4an Brase

Haben Sie sich die Implementierung von Arrays.copyOf () von Sun angeschaut?

 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;
}

Wie zu sehen ist, wird System.arraycopy() intern verwendet, die Leistung wäre also gleich.

11
matsev

System.arrayCopy ist nativ implementiert und daher schneller als jeder Java-Code. Ich empfehle dir, es zu benutzen.

3
Humphrey Bogart

Anstatt zu diskutieren, sind dies die tatsächlichen Ergebnisse. Ihre Wahl hängt natürlich davon ab, wie viele Daten Sie kopieren möchten.

leistungstest für Byte [] -Kopie

10.000.000 Iterationen 40b array.copyOfRange: 135 ms systems.arraycopy: 141 ms

10.000.000 Iterationen 1000b array.copyOfRange: 1861 ms systems.arraycopy: 2211 ms

10.000.000 Iterationen 4000b array.copyOfRange: 6315ms systems.arraycopy: 5251ms

1.000.000 Iterationen 100.000 b array.copyOfRange: 15.198 ms systems.arraycopy: 14783 ms

1
cyberthreat

Wenn Sie sich den Quellcode für System.arraycopy () von und Array.copyOf () ansehen, wird die Leistung verbessert. 

System.arraycopy () ist C-Code, arbeitet direkt in Ihrem Array, gibt keine Werte zurück und sollte daher viel schneller als Array.copyOf () arbeiten. Wenn Sie jedoch ein neues Array erstellen möchten oder nur den Wert des Kopiervorgangs benötigen, müssen Sie dafür ein neues Array erstellen. Legen Sie die neue Arraylänge usw. fest. Dies ist nicht möglich eine Rückgabe System.arraycopy (Quelle, 0, Ziel, 0, Länge).

Für das, was Array.copyOf () dann tun kann, wird ein neues Array für Sie erstellt. Sie können den Rückgabewert von Array.copyOf () einem Array zuweisen oder ihn von einer Methode als Array.copyOf () zurückgeben, um einen Wert an Sie zurückzugeben, anstatt direkt in Ihrem Zielarray zu arbeiten. So wird Ihr Code viel sauberer aussehen. Nichtsdestotrotz ist Array.copyOf () eine generische Typmethode für die Performance, und sie weiß nicht im Voraus, mit welcher Methode sie arbeiten wird. Daher muss Array.newInstance () oder new Object () aufgerufen und dann in den Array-Typ der Eingabe umgewandelt werden.

Also zusammenfassend. Verwenden Sie System.arraycopy () wegen der Leistung. Verwenden Sie Array.copyOf () für saubereren Code.

0
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