2010-04-07 13 views
59

Il metodo toArray in ArrayList, Bloch utilizza sia System.arraycopy che Arrays.copyOf per copiare un array.Cosa è più efficiente: System.arraycopy vs 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; 
} 

Come confrontare questi due metodi di copia, quando utilizzare quale?

+1

ciò che è "Bloch"? Perché lo snippet di codice è pertinente? –

+2

@Ciro Bloch è il tizio che ha scritto l'implementazione di ArrayList. – Insomniac

+0

Vedere anche: https://stackoverflow.com/q/44487304/14955 – Thilo

risposta

86

La differenza è che Arrays.copyOf non copia solo gli elementi, ma crea anche un nuovo array. System.arrayCopy copie in un array esistente.

Ecco la fonte per Arrays.copyOf, come si può vedere utilizza System.arraycopy internamente per riempire il nuovo array.

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

È ovvio .... Arrays.copyOf dovrebbe creare una nuova istanza di array come non ne stiamo passando uno; mentre passiamo una destinazione a System.arraycopy. Per quanto riguarda la velocità, ovviamente ovviamente System.arraycopy dovrebbe vincere in quanto è un metodo nativo e in definitiva Arrays.copyOf chiama anche questo metodo per copiare un array. –

+2

L'origine Java [non importa] (https://stackoverflow.com/questions/44487304/why-arrays-copyof-is-2-times-faster-than-system-arraycopy-for-small-arrays#comment75970318_44487304) poiché l'intrinseco è stato creato. – maaartinus

11

System.arrayCopy è molto più veloce. È nel sistema perché utilizza una copia di memoria diretta al di fuori della terra di Java. Usalo quando è possibile.

+1

Ma System.arraycopy copia solo in una matrice esistente. Arrays.copyOf crea anche l'array di output per te. – Thilo

+2

Questo è vero, e fintanto che stai usando System.arraycopy sotto le copertine qualunque sia il wrapper di convenienza che usi è solo una salsa. –

+4

E, in alcuni casi, 'System.arrayCopy' * non può * utilizzare una copia di memoria diretta. –

3

System.arrayCopy è implementato in modo nativo e quindi sarà più veloce di qualsiasi codice Java. Ti raccomando di usarlo.

+4

Solo perché usa il codice nativo tramite JNI, non significa che sarà più veloce: http://www.javaspecialists.eu/archive/Issue124.html – Dag

31

Mentre System.arraycopy è implementato nativamente, ed è quindi potrebbe essere più veloce di un ciclo di Java, non è sempre veloce come ci si potrebbe aspettare. Considerate questo esempio:

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

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

In questo caso, il tipo di base dei foo e bar array hanno diversi tipi di base, per cui la realizzazione di arraycopy deve verificare il tipo di ogni riferimento copiato per assicurarsi che sia effettivamente un riferimento a un'istanza di String. Questo è significativamente più lento di un semplice memcopy in stile C dei contenuti dell'array.

L'altro punto è che Arrays.copyOf utilizza System.arraycopy sotto il cofano, quindi il risparmio che si ottiene creando un nuovo array e riempiendolo manualmente utilizzando arraycopy sarebbe minimo. Supponendo che questo è ciò che stai cercando di fare ...

Il mio consiglio sarebbe quello di utilizzare la versione che rende il codice più facile da leggere, e solo preoccuparsi che uno è più veloce se profiling ti dice che è importante.


1 - E 'potrebbe essere più veloce, ma è anche possibile che il compilatore JIT fa un buon lavoro di ottimizzazione di un ciclo a mano il codice che non c'è differenza tale.

+1

+1 per indicare il tipo di controllo che deve avvenire a volte. – Thilo

+0

@StephenC, Per quanto riguarda il primo paragrafo, ci sono casi in cui 'System.arrayCopy' potrebbe essere * più lento *? – Pacerier

+0

@Pacerier: non ne sono a conoscenza. Ma non è impossibile. –

12

Se si desidera un esatto copia di una matrice (ad esempio, se si vuole fare una copia di difesa), il modo più efficace di copiare un array è probabilmente utilizzando clone() metodo dell'oggetto array:

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

Non mi sono preso la briga di testare le sue prestazioni, ma ha buone possibilità di essere piuttosto veloce dato che è tutto nativo (allocazione e copia in chiamata), e la clonazione è una specie di speciale modo JVM di copiare oggetti (ed è per lo più malvagio per altri scopi) ed è probabile che sia in grado di prendere alcune "scorciatoie".

Personalmente, userei ancora clone se fosse più lento di qualsiasi altro modo di copiare, perché è più facile da leggere e quasi impossibile da rovinare durante la scrittura. System.arrayCopy, d'altra parte ...

+1

Esatto, ma 'System.arrayCopy' è anch'esso nativo (ed è dedicato a tale attività) mentre' clone' sembra avere a che fare con molte * condizioni * ... – Pacerier

+0

@Pacerier "Non uso spesso' clone' ... ma quando lo faccio lo uso sugli array. " – gustafc

+0

Stavo parlando di * that * '.clone()' quando usato sugli array ....In ogni caso, restituisce ancora un oggetto che deve quindi essere reintegrato in un array (= lavoro aggiuntivo). – Pacerier

10

Hai guardato all'implementazione di Arrays.copyOf() del Sole?

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

Come si vede, utilizza System.arraycopy() internamente, per cui le prestazioni sarebbe la stessa.

0
 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

Invece di discutere, questi sono i risultati effettivi. Chiaramente, la tua scelta dipenderà dalla quantità di dati che desideri copiare.

byte [] copia di prova delle prestazioni

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

10.000.000 iterazioni 1000B array.copyOfRange: 1861ms systems.arraycopy: 2211ms

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

1.000.000 iterazioni 100,000b array.copyOfRange: 15,198ms systems.arraycopy: 14783ms

Problemi correlati