Czy istnieje odpowiednik memcpy () w Javie?

83

Mam bajt [] i chciałbym go skopiować do innego bajtu []. Może pokazuję tutaj moje proste tło „C”, ale czy istnieje odpowiednik memcpy () w tablicach bajtowych w Javie?

Szymon
źródło

Odpowiedzi:

86

Możesz spróbować System.arraycopylub skorzystać z funkcji tablicowych w takiej Arraysklasie java.util.Arrays.copyOf. Oba powinny zapewniać natywną wydajność pod maską.

Arrays.copyOf jest prawdopodobnie korzystny dla czytelności, ale został wprowadzony dopiero w java 1.6.

 byte[] src = {1, 2, 3, 4};
 byte[] dst = Arrays.copyOf(src, src.length);
 System.out.println(Arrays.toString(dst));
Tomek
źródło
Myślę, że druga opcja jest bardziej „logiczna”. Nigdy nie rozumiałem, dlaczego System.arraycopy () jest tam, gdzie jest, jedną z najmniejszych możliwych lokalizacji.
sinuhepop
@Sinuhe - jest tam z powodów historycznych.
Stephen C,
30
To NIE jest poprawna odpowiedź. memcpy () nie przydziela danych, tylko kopiuje do istniejącego bufora. Podczas gdy Arrays.copyOf () wyraźnie przydzielają nową pamięć.
splinux
105

Użyj System.arraycopy ()

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

Przykład,

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


lub użyj Arrays.copyOf ()
Przykład,

target = Arrays.copyOf(source, length);

java.util.Arrays.copyOf(byte[] source, int length)został dodany w JDK 1.6. Metoda wykorzystuje zrobić kopię tablicy, ale jest bardziej elastyczny niż ponieważ można zrobić kopie części tablicy.

copyOf()System.arrayCopy()clone()

Zaki
źródło
5
Arrays.copyOf () również przydziela pamięć. w twoim przykładzie, jeśli zmienisz String [] target = new String [4]; a następnie target = Arrays.copyOf () tworzy nowy cel, którym jest String [3]. Nie zachowanie memcopy.
MikeF
Arrays.copyOf wewnętrznie używa System.arraycopy, który jest metodą natywną.
Gajraj Tanwar
10

Jeśli potrzebujesz tylko dokładnej kopii jednowymiarowej tablicy, użyj clone().

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

W przypadku innych operacji kopiowania tablicy użyj System.arrayCopy/ Arrays.copyOftak, jak sugeruje Tom .

Generalnie clonenależy tego unikać, ale jest to wyjątek od reguły.

McDowell
źródło
Zobacz także więcej szczegółów w zaakceptowanej odpowiedzi na stackoverflow.com/questions/3208899/… .
Andy Thomas,
5

Możesz użyć System.arrayCopy . Kopiuje elementy z tablicy źródłowej do tablicy docelowej. Implementacja Sun wykorzystuje zoptymalizowany ręcznie asembler, więc jest to szybkie.

mdma
źródło
3

W rzeczywistości Java ma coś podobnego do memcpy (). Klasa Unsafe ma metodę copyMemory (), która jest zasadniczo identyczna z memcpy (). Oczywiście, podobnie jak memcpy (), nie zapewnia ochrony przed nakładaniem się pamięci, zniszczeniem danych itp. Nie jest jasne, czy jest to rzeczywiście memcpy () czy memmove (). Można go używać do kopiowania adresów rzeczywistych na adresy rzeczywiste lub odwołań do odwołań. Zwróć uwagę, że jeśli używane są odniesienia, musisz podać przesunięcie (w przeciwnym razie JVM umrze jak najszybciej).

Unsafe.copyMemory () działa (do 2 GB na sekundę na moim starym, zmęczonym komputerze). Używaj na własne ryzyko. Należy zauważyć, że klasa Unsafe nie istnieje dla wszystkich implementacji maszyny JVM.

Peter Schaeffer
źródło
przepraszam za to, że zajmowałem się sematarium dla zwierząt domowych w tym starożytnym wątku, ale czy możesz mi podać przykład, jak to zrobić, z szeregiem odniesień. I czy jest szybszy w przypadku małych ilości danych (np. 1-4 MB), czy po prostu warty w przypadku większych danych, takich jak wspomniane 2 GB?
FinnTheHuman
2
Używanie tej sun.misc.Unsafeklasy jest uważane za złą praktykę "hack", bo jest to prywatna klasa pakietu. Ponadto, począwszy od Java 9, nie będzie już dostępna, więc próba użycia tej klasy jest tym samym, co błaganie o nieoczekiwane zepsucie kodu.
code_dredd
2

Jeśli używasz JDK 1.5+, powinieneś używać

System.arraycopy()

Zamiast

Arrays.copyOfRange()

Beacuse Arrays.copyOfRange () nie został dodany do JDK 1.6, więc możesz dostać

Java - “Cannot Find Symbol” error

podczas wywoływania Arrays.copyOfRange w tej wersji JDK.

Amila Weerasinghe
źródło
0

Użyj byteBufferViewVarHandle lub byteArrayViewVarHandle.

Umożliwi to skopiowanie tablicy „longs” bezpośrednio do tablicy „double” i podobne z czymś takim:

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

To pozwoli ci zrobić trochę hakowania, takie jak:

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);
Molossus Spondee
źródło
0

Nie. Java nie ma odpowiednika memcpy. memmoveZamiast tego Java ma odpowiednik .

Jeśli argumenty src i dest odwołują się do tego samego obiektu tablicy, to kopiowanie jest wykonywane tak, jakby komponenty w pozycjach od srcPos do srcPos + length-1 zostały najpierw skopiowane do tymczasowej tablicy ze składnikami długości, a następnie zawartość tymczasowej tablicy została skopiowane na pozycje od destPos do destPos + długość-1 tablicy docelowej.

Oracle Docs

Jest bardzo prawdopodobne, System.arraycopyże nigdy nie będzie miał takiej samej wydajności, jak memcpygdyby srci destodnosił się do tej samej macierzy. Zwykle będzie to jednak wystarczająco szybkie.

Molossus Spondee
źródło