Die toArray
Methode in ArrayList
Bloch verwendet beide System.arraycopy
und, 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?
java
arrays
performance
Sawyer
quelle
quelle
Antworten:
Der Unterschied besteht darin, dass
Arrays.copyOf
nicht nur Elemente kopiert, sondern auch ein neues Array erstellt wird.System.arraycopy
kopiert in ein vorhandenes Array.Hier ist die Quelle für
Arrays.copyOf
, wie Sie sehen können, dieSystem.arraycopy
intern verwendet wird, um das neue Array zu fü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; }
quelle
System.arraycopy
hat mehr detaillierte Parameter, können Sie Startindex für beide Arrays angeben.Während
System.arraycopy
es nativ implementiert ist und daher 1 schneller als eine Java-Schleife sein könnte, ist es nicht immer so schnell, wie Sie es 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 Arrays
foo
und diebar
Arrays unterschiedliche Basistypen. Daher muss bei der Implementierung vonarraycopy
der Typ jeder kopierten Referenz überprüft werden, um sicherzustellen, dass es sich tatsächlich um eine Referenz auf eine String-Instanz handelt. Das ist deutlich langsamer als ein einfacher C-Stilmemcopy
des Array-Inhalts.Der andere Punkt ist , dass
Arrays.copyOf
AnwendungenSystem.arraycopy
unter der Motorhaube. DaherSystem.arraycopy
ist auf den ersten Blick nicht langsamer 2 alsArrays.copyOf
. Aber man kann (aus dem Code zitiert siehe oben ) , dassArrays.copyOf
in einigen Fällen eine Reflexion verwenden Sie das neue Array zu erstellen. Der Leistungsvergleich ist also nicht einfach.Diese Analyse weist einige Mängel auf.
Wir betrachten den Implementierungscode einer bestimmten Java-Version. Diese Methoden können sich ändern und frühere Annahmen zur Effizienz ungültig machen.
Wir ignorieren die Möglichkeit, dass der JIT-Compiler eine clevere Spezialfalloptimierung für diese Methoden durchführen könnte. Und es passiert anscheinend mit
Arrays.copyOf
; Siehe Warum ist Arrays.copyOf für kleine Arrays 2-mal schneller als System.arraycopy? . Diese Methode ist in Java-Implementierungen der aktuellen Generation "intrinsisch", was bedeutet, dass der JIT-Compiler ignoriert, was im Java-Quellcode enthalten ist!In beiden Fällen ist der Unterschied zwischen den beiden Versionen
O(1)
(dh unabhängig von der Arraygröße) relativ gering. Daher würde ich raten, die Version zu verwenden, mit der Ihr Code am einfachsten zu lesen ist, und sich nur darum zu kümmern, welche schneller ist, wenn die Profilerstellung Ihnen sagt, dass dies wichtig ist.1 - Es könnte schneller sein, aber es ist auch möglich, dass der JIT-Compiler eine handcodierte Schleife so gut optimiert, dass es keinen Unterschied gibt.
quelle
System.arrayCopy
es tatsächlich langsamer sein könnte ?arraycopy
Anruf durchgeführt werden kann, die bei einem indirekten Anruf nicht möglich ist. All diese Dinge sind möglich ... wenn nicht plausibel.Wenn Sie eine genaue Kopie eines Arrays wünschen (z. B. wenn Sie eine defensive Kopie erstellen möchten), ist die
clone()
Methode des Array-Objekts wahrscheinlich die effektivste Methode zum Kopieren eines Arrays :class C { private int[] arr; public C(int[] values){ this.arr = values.clone(); } }
Ich habe mir nicht die Mühe gemacht, die Leistung zu testen, aber es besteht eine gute Chance, ziemlich schnell zu sein, da alles nativ ist (Zuweisung und Kopieren im Anruf), und das Klonen ist eine Art besondere, von JVM gesegnete Art, Objekte zu kopieren (und das ist es auch meistens böse für andere Zwecke) und ist wahrscheinlich in der Lage, einige "Abkürzungen" zu nehmen.
Persönlich würde ich immer noch verwenden,
clone
wenn es langsamer als jede andere Art des Kopierens wäre, weil es einfacher zu lesen und nahezu unmöglich ist, beim Schreiben Fehler zu machen.System.arrayCopy
, auf der anderen Seite...quelle
System.arrayCopy
ist auch einheimisch (und es ist dieser Aufgabe gewidmet), währendclone
es mit vielen Bedingungen zuclone
... aber wenn ich es tue, benutze ich es auf Arrays.".clone()
wenn es auf Arrays verwendet wird ... Auf jeden Fall gibt es immer noch ein Objekt zurück, das dann wieder in ein Array umgewandelt werden muss (= zusätzliche Arbeit).clone()
schneller sein wird als native,System.arrayCopy
weil sieclone()
sich auch dieser Aufgabe widmet?System.arrayCopy ist viel schneller. Es ist im System, weil es eine direkte Speicherkopie außerhalb von Java Land verwendet. Verwenden Sie es, wenn möglich.
quelle
System.arrayCopy
keine direkte Speicherkopie verwendet werden kann.Haben Sie sich die Implementierung von Arrays.copyOf () durch Sun angesehen?
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 es
System.arraycopy()
intern verwendet, sodass die Leistung gleich ist.quelle
System.arrayCopy
wird nativ implementiert und ist daher schneller als jeder Java-Code. Ich empfehle Ihnen, es zu verwenden.quelle
Anstatt zu debattieren, sind dies die tatsächlichen Ergebnisse. Ihre Wahl hängt natürlich davon ab, wie viele Daten Sie kopieren möchten.
Byte [] Kopierleistungstest
10.000.000 Iterationen 40b array.copyOfRange: 135ms systems.arraycopy: 141ms
10.000.000 Iterationen 1000b array.copyOfRange: 1861ms systems.arraycopy: 2211ms
10.000.000 Iterationen 4000b array.copyOfRange: 6315ms systems.arraycopy: 5251ms
1.000.000 Iterationen 100.000b array.copyOfRange: 15.198 ms systems.arraycopy: 14783 ms
quelle
Wenn Sie sich sowohl den Quellcode für System.arraycopy () von als auch Array.copyOf () für die Leistung ansehen.
System.arraycopy () ist C-Code, arbeitet direkt auf Ihrem Array, gibt keine Werte zurück und sollte daher viel schneller als Array.copyOf () arbeiten. Wenn Sie jedoch ein neues Array erstellen müssen oder nur den Wert des Kopiervorgangs benötigen, müssen Sie dafür ein neues Array erstellen, die neue Array-Länge festlegen usw. Dies ist also 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 zurückgeben, da Array.copyOf () Ihnen einen Wert zurückgibt, anstatt direkt auf Ihrem Zielarray zu arbeiten. Somit sieht Ihr Code viel sauberer aus. Aus Gründen der Leistung ist Array.copyOf () jedoch eine generische Typmethode, die nicht im Voraus weiß, mit was sie arbeiten wird. Daher muss Array.newInstance () oder new Object () aufgerufen und dann in den Array-Typ der Eingabe umgewandelt werden.
Also um es zusammenzufassen. Verwenden Sie System.arraycopy () aus Leistungsgründen. Verwenden Sie Array.copyOf () für saubereren Code.
quelle
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)); } }
quelle