¿Existe un equivalente a memcpy () en Java?

81

Tengo un byte [] y me gustaría copiarlo en otro byte []. Tal vez esté mostrando mi fondo simple 'C' aquí, pero ¿existe un equivalente a memcpy () en matrices de bytes en Java?

Simón
fuente

Respuestas:

84

Puede probar System.arraycopyo hacer uso de funciones de matriz en la Arraysclase como java.util.Arrays.copyOf. Ambos deberían brindarte un rendimiento nativo bajo el capó.

Arrays.copyOf es probablemente favorable para la legibilidad, pero solo se introdujo en java 1.6.

 byte[] src = {1, 2, 3, 4};
 byte[] dst = Arrays.copyOf(src, src.length);
 System.out.println(Arrays.toString(dst));
Tom
fuente
Creo que la segunda opción es más "lógica". Nunca entendí por qué System.arraycopy () está donde está, una de las ubicaciones más torpes posibles.
sinuhepop
@Sinuhe - está ahí por razones históricas.
Stephen C
29
Ésta NO es la respuesta correcta. memcpy () no asigna datos, solo copia a un búfer existente. Mientras que Arrays.copyOf () claramente asigna nueva memoria.
splinux
102

Utilice System.arraycopy ()

System.arraycopy(sourceArray, 
                 sourceStartIndex,
                 targetArray,
                 targetStartIndex,
                 length);

Ejemplo,

String[] source = { "alpha", "beta", "gamma" };
String[] target = new String[source.length];
System.arraycopy(source, 0, target, 0, source.length);


o use Arrays.copyOf ()
Example,

target = Arrays.copyOf(source, length);

java.util.Arrays.copyOf(byte[] source, int length)se agregó en JDK 1.6.

El copyOf()método se usa System.arrayCopy()para hacer una copia de la matriz, pero es más flexible clone()ya que puede hacer copias de partes de una matriz.

Zaki
fuente
5
Arrays.copyOf () también asigna memoria. en su ejemplo, si cambia String [] target = new String [4]; y luego target = Arrays.copyOf () crea un nuevo objetivo que es un String [3]. No es el comportamiento de Memcopy.
MikeF
Arrays.copyOf utiliza internamente System.arraycopy, que es un método nativo.
Gajraj Tanwar
8

Si solo desea una copia exacta de una matriz unidimensional, use clone().

byte[] array = { 0x0A, 0x01 };
byte[] copy = array.clone();

Para otras operaciones de copia de matriz, use System.arrayCopy/ Arrays.copyOfcomo sugiere Tom .

En general, clonedebe evitarse, pero esto es una excepción a la regla.

McDowell
fuente
Consulte también más detalles en la respuesta aceptada a stackoverflow.com/questions/3208899/… .
Andy Thomas
5

Puede utilizar System.arrayCopy . Copia elementos de una matriz de origen a una matriz de destino. La implementación de Sun utiliza un ensamblador optimizado a mano, por lo que es rápido.

mdma
fuente
3

Java en realidad tiene algo como memcpy (). La clase Unsafe tiene un método copyMemory () que es esencialmente idéntico a memcpy (). Por supuesto, como memcpy (), no proporciona protección contra superposiciones de memoria, destrucción de datos, etc. No está claro si realmente es un memcpy () o un memmove (). Se puede utilizar para copiar de direcciones reales a direcciones reales o de referencias a referencias. Tenga en cuenta que si se utilizan referencias, debe proporcionar un desplazamiento (o la JVM morirá lo antes posible).

Unsafe.copyMemory () funciona (hasta 2 GB por segundo en mi vieja PC cansada). Úselo bajo su propio riesgo. Tenga en cuenta que la clase Unsafe no existe para todas las implementaciones de JVM.

Peter Schaeffer
fuente
perdón por irme de mascotas en este antiguo hilo, pero ¿podría darme un ejemplo sobre cómo hacerlo con una serie de referencias? ¿Y es más rápido para pequeñas cantidades de datos (como 1-4 MB) o simplemente vale la pena en el caso de datos más grandes como los 2GB que mencionaste?
FinnTheHuman
2
Usar la sun.misc.Unsafeclase se considera una mala práctica "piratear" porque es una clase de paquete privado . Además, a partir de Java 9, ya no estará disponible, por lo que intentar usar esta clase es lo mismo que pedir que su código se rompa inesperadamente.
code_dredd
0

Utilizar byteBufferViewVarHandle o byteArrayViewVarHandle.

Esto le permitirá copiar una matriz de "largos" directamente a una matriz de "dobles" y similares con algo como:

public long[] toLongs(byte[] buf) {
    int end = buf.length >> 3;
    long[] newArray = new long[end];
    for (int ii = 0; ii < end; ++ii) {
        newArray[ii] = (long)AS_LONGS_VH.get(buf, ALIGN_OFFSET + ii << 3);
    }
}

private static final ALIGN_OFFSET = ByteBuffer.wrap(new byte[0]).alignmentOffset(8); 
private static final VarHandle AS_LONGS_VH = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.nativeOrder());

Esto le permitirá hacer un poco de pirateo como:

float thefloat = 0.4;
int floatBits;
_Static_assert(sizeof theFloat == sizeof floatBits, "this bit twiddling hack requires floats to be equal in size to ints");
memcpy(&floatBits, &thefloat, sizeof floatBits);
Moloso Spondee
fuente
0

No. Java no tiene equivalente a memcpy. Java tiene un equivalente a en su memmovelugar.

Si los argumentos src y dest se refieren al mismo objeto de matriz, entonces la copia se realiza como si los componentes en las posiciones srcPos a srcPos + length-1 se copiaran primero a una matriz temporal con componentes de longitud y luego se copiaran los contenidos de la matriz temporal. copiado en las posiciones destPos a destPos + longitud-1 de la matriz de destino.

Documentos de Oracle

Es muy probable System.arraycopyque nunca tenga el mismo rendimiento que memcpysi srcy se destrefiera a la misma matriz. Sin embargo, normalmente esto será lo suficientemente rápido.

Moloso Spondee
fuente