2010-04-07 11 views
59

El método toArray en ArrayList, Bloch usa System.arraycopy y Arrays.copyOf para copiar una matriz.¿Qué es más eficiente: 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; 
} 

Cómo comparar estos dos métodos de copia, cuándo usarlos?

+1

¿Qué es "Bloch"? ¿Por qué es relevante el fragmento de código? –

+2

@Ciro Bloch es el tipo que escribió la implementación de ArrayList. – Insomniac

+0

Vea también: https://stackoverflow.com/q/44487304/14955 – Thilo

Respuesta

86

La diferencia es que Arrays.copyOf no solo copia elementos, sino que también crea una nueva matriz. System.arrayCopy copias en una matriz existente.

Aquí está la fuente para Arrays.copyOf, como se puede ver utiliza System.arraycopy internamente para llenar la nueva matriz.

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

Es obvio ... Arrays.copyOf debería crear una nueva instancia de array ya que no le estamos pasando uno; mientras pasamos un destino a System.arraycopy. Con respecto a la velocidad, nuevamente obviamente System.arraycopy debería ganar ya que es un método nativo y, en última instancia, Arrays.copyOf también llama a este método para copiar una matriz. –

+2

La fuente de Java [no importa] (https://stackoverflow.com/questions/44487304/why-arrays-copyof-is-2-times-faster-than-system-arraycopy-for-small-arrays#comment75970318_44487304) ya que lo intrínseco fue creado. – maaartinus

11

System.arrayCopy es mucho más rápido. Está en el sistema porque usa una copia de memoria directa fuera de Java. Úselo cuando sea posible.

+1

Pero System.arraycopy solo copia en una matriz existente. Arrays.copyOf también crea la matriz de salida para usted. – Thilo

+2

Eso es cierto, y siempre que esté utilizando System.arraycopy debajo de las cubiertas, cualquier envoltura de conveniencia que use es simplemente gravy. –

+4

Y, hay casos donde 'System.arrayCopy' * no puede * usar una copia de memoria directa. –

3

System.arrayCopy se implementa de forma nativa, y por lo tanto será más rápido que cualquier código de Java. Te recomiendo que lo uses.

+4

El hecho de que utilice código nativo a través de JNI no significa que sea más rápido: http://www.javaspecialists.eu/archive/Issue124.html – Dag

31

Mientras System.arraycopy se implementa de forma nativa, y por lo tanto es podría ser más rápido que un bucle de Java, que no siempre es tan rápido como se podría esperar. Considere este ejemplo:

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

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

En este caso, el tipo de base de los foo y bar matrices tienen diferentes tipos de bases, por lo que la implementación de arraycopy tiene que comprobar el tipo de cada referencia copiado para asegurarse de que en realidad es una referencia a una instancia de cadena. Eso es significativamente más lento que una simple memcopy de estilo C del contenido de la matriz.

El otro punto es que Arrays.copyOf utiliza System.arraycopy bajo el capó, por lo que el ahorro a alcanzar mediante la creación de una nueva matriz y llenar por sí mismo utilizando arraycopy sería mínimo. Suponiendo que eso es lo que tratamos de hacer ...

Mi consejo sería utilizar la versión que hace el código más fácil de leer, y sólo preocuparse de cuál es más rápido si perfiles le dice que es importante.


1 - Se podría ser más rápido, pero es también es posible que el compilador JIT hace un buen trabajo de optimización de un lazo de mano de código que no hay ninguna diferencia.

+1

+1 para señalar la verificación de tipo que tiene que realizarse a veces. – Thilo

+0

@StephenC, En cuanto a su primer párrafo, ¿hay casos en que 'System.arrayCopy' en realidad podría ser * más lento *? – Pacerier

+0

@Pacerier - No conozco ninguno. Pero no es imposible. –

12

Si desea una exacta copia de una matriz (por ejemplo, si usted quiere hacer una copia defensiva), la forma más eficaz de copiar un array es probable que el uso de clone() el método del objeto de matriz:

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

No me he tomado la molestia de probar el rendimiento de la misma, pero existe una buena posibilidad de ser bastante rápido ya que es completamente nativa (asignación y copia en llamada), y la clonación es una forma especial de copiar objetos de JVM (y es principalmente malo para otros propósitos) y es probable que pueda tomar algunos "atajos".

Personalmente, seguiría usando clone si fuera más lento que con cualquier otra forma de copiado, porque es más fácil de leer y casi imposible de estropear al escribir. System.arrayCopy, por otro lado ...

+1

Correcto, pero 'System.arrayCopy' también es nativo (y está dedicado a esa tarea) mientras que' clone' parece tener que lidiar con muchas * condiciones * ... – Pacerier

+0

@Pacerier "No suelo usar' clonar ... pero cuando lo hago, lo uso en matrices ". – gustafc

+0

Estaba hablando de * que * '.clone()' cuando se usa en arreglos ....En cualquier caso, aún devuelve un Objeto que luego debe ser devuelto a una matriz (= trabajo adicional). – Pacerier

10

¿Has visto la implementación de Arrays.copyOf() en Sun?

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

Como puede verse, se utiliza System.arraycopy() internamente, por lo que el rendimiento sería el mismo.

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

En lugar de debatir, estos son los resultados reales. Claramente, su elección dependerá de la cantidad de datos que quiera copiar.

byte [] copia de prueba de rendimiento

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

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

10,000,000 iteraciones 4000b array.copyOfRange: 6315ms systems.arraycopy: 5251ms

1.000.000 iteraciones 100.000b array.copyOfRange: 15,198ms systems.arraycopy: 14783ms

Cuestiones relacionadas