Gibt es in Java ein Äquivalent zu memcpy ()?

81

Ich habe ein Byte [] und möchte es in ein anderes Byte [] kopieren. Vielleicht zeige ich hier meinen einfachen 'C'-Hintergrund, aber gibt es ein Äquivalent zu memcpy () auf Byte-Arrays in Java?

Simon
quelle

Antworten:

84

Sie können versuchen System.arraycopy, Array-Funktionen in der ArraysKlasse wie zu verwenden java.util.Arrays.copyOf. Beide sollten Ihnen native Leistung unter der Haube bieten.

Arrays.copyOf ist wahrscheinlich günstig für die Lesbarkeit, wurde jedoch nur in Java 1.6 eingeführt.

 byte[] src = {1, 2, 3, 4};
 byte[] dst = Arrays.copyOf(src, src.length);
 System.out.println(Arrays.toString(dst));
Tom
quelle
Ich denke, die zweite Option ist "logischer". Ich habe nie verstanden, warum System.arraycopy () wo ist, einer der ungeschicktesten möglichen Orte.
Sinuhepop
@ Sinhe - es ist aus historischen Gründen da.
Stephen C
29
Dies ist NICHT die richtige Antwort. memcpy () ordnet keine Daten zu, sondern kopiert nur in einen vorhandenen Puffer. Während Arrays.copyOf () eindeutig neuen Speicher zuweist.
Splinux
102

Verwenden Sie System.arraycopy ()

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

Beispiel,

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


oder verwenden Sie Arrays.copyOf ()
Beispiel,

target = Arrays.copyOf(source, length);

java.util.Arrays.copyOf(byte[] source, int length)wurde in JDK 1.6 hinzugefügt.

Die copyOf()Methode wird System.arrayCopy()zum Erstellen einer Kopie des Arrays verwendet, ist jedoch flexibler als clone()das Kopieren von Teilen eines Arrays.

Zaki
quelle
5
Arrays.copyOf () weist auch Speicher zu. in Ihrem Beispiel, wenn Sie String [] ändern target = new String [4]; und dann target = Arrays.copyOf () erstellt es ein neues Ziel, das ein String ist [3]. Nicht das Memcopy-Verhalten.
MikeF
Arrays.copyOf verwendet intern System.arraycopy, eine native Methode.
Gajraj Tanwar
8

Wenn Sie nur eine exakte Kopie eines eindimensionalen Arrays wünschen, verwenden Sie clone().

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

Verwenden Sie für andere Array-Kopiervorgänge System.arrayCopy/, Arrays.copyOfwie von Tom vorgeschlagen .

Im Allgemeinen clonesollte vermieden werden, aber dies ist eine Ausnahme von der Regel.

McDowell
quelle
Weitere Einzelheiten finden Sie in der akzeptierten Antwort auf stackoverflow.com/questions/3208899/… .
Andy Thomas
5

Sie können System.arrayCopy verwenden . Es kopiert Elemente von einem Quellarray in ein Zielarray. Die Sun-Implementierung verwendet einen handoptimierten Assembler, sodass dies schnell geht.

mdma
quelle
3

Java hat tatsächlich so etwas wie memcpy (). Die Unsafe-Klasse verfügt über eine copyMemory () -Methode, die im Wesentlichen mit memcpy () identisch ist. Natürlich bietet es wie memcpy () keinen Schutz vor Speicherüberlagerungen, Datenvernichtung usw. Es ist nicht klar, ob es sich wirklich um memcpy () oder memmove () handelt. Es kann verwendet werden, um von tatsächlichen Adressen zu tatsächlichen Adressen oder von Verweisen zu Referenzen zu kopieren. Beachten Sie, dass Sie bei Verwendung von Referenzen einen Offset angeben müssen (sonst stirbt die JVM so schnell wie möglich).

Unsafe.copyMemory () funktioniert (bis zu 2 GB pro Sekunde auf meinem alten müden PC). Benutzung auf eigene Gefahr. Beachten Sie, dass die unsichere Klasse nicht für alle JVM-Implementierungen vorhanden ist.

Peter Schaeffer
quelle
Es tut mir leid, dass Sie in diesem alten Thread alle Tier-Sematare gelesen haben, aber können Sie mir ein Beispiel geben, wie das mit einer Reihe von Referenzen geht? Und ist es schneller für kleine Datenmengen (wie 1-4 MB) oder nur für größere Datenmengen wie die von Ihnen erwähnten 2 GB geeignet?
FinnTheHuman
2
Die Verwendung der sun.misc.UnsafeKlasse wird als schlechte Praxis angesehen. "Hack" b / c ist eine private Paketklasse. Ab Java 9 ist es außerdem nicht mehr verfügbar. Der Versuch, diese Klasse zu verwenden, entspricht dem Bitten, dass Ihr Code unerwartet unterbrochen wird.
code_dredd
0

Verwenden Sie byteBufferViewVarHandle oder byteArrayViewVarHandle.

Auf diese Weise können Sie ein Array von "Longs" direkt in ein Array von "Doubles" und Ähnlichem kopieren.

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());

Auf diese Weise können Sie Folgendes tun:

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);
Steven Stewart-Gallus
quelle
0

Nein, Java hat kein Äquivalent zu memcpy. Java hat memmovestattdessen ein Äquivalent zu .

Wenn sich die Argumente src und dest auf dasselbe Array-Objekt beziehen, wird das Kopieren so ausgeführt, als ob die Komponenten an den Positionen srcPos bis srcPos + length-1 zuerst in ein temporäres Array mit Längenkomponenten kopiert wurden und dann der Inhalt des temporären Arrays kopiert in Positionen destPos über destPos + Länge-1 des Zielarrays.

Oracle Docs

Es ist sehr wahrscheinlich, dass System.arraycopyes niemals die gleiche Leistung wie memcpywenn hat srcund destsich auf dasselbe Array bezieht. Normalerweise ist dies jedoch schnell genug.

Steven Stewart-Gallus
quelle