Чи існує еквівалент memcpy () в Java?


83

У мене є байт [], і я хотів би скопіювати його в інший байт []. Можливо, я показую тут свій простий фон "C", але чи існує еквівалент memcpy () на байтових масивах у Java?

Відповіді:


86

Ви можете спробувати System.arraycopyабо використати функції масиву в Arraysкласі, наприклад java.util.Arrays.copyOf. І те, і інше повинно забезпечити вам природну ефективність під капотом.

Arrays.copyOf, ймовірно, сприятливий для читабельності, але був представлений лише в Java 1.6.

 byte[] src = {1, 2, 3, 4};
 byte[] dst = Arrays.copyOf(src, src.length);
 System.out.println(Arrays.toString(dst));

Думаю, другий варіант є більш «логічним». Я ніколи не розумів, чому System.arraycopy () - це де є, одне з найбільш незграбних можливих розташувань.
sinuhepop

@Sinuhe - це є з історичних причин.
Stephen C

30
Це НЕ правильна відповідь. memcpy () не виділяє дані, а лише копіює в існуючий буфер. Тоді як Arrays.copyOf () чітко виділяє нову пам'ять.
splinux

105

Використовуйте System.arraycopy ()

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

Приклад,

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


або скористайтеся прикладом Arrays.copyOf ()
,

target = Arrays.copyOf(source, length);

java.util.Arrays.copyOf(byte[] source, int length)було додано в JDK 1.6. Метод використовує , щоб зробити копію масиву, але є більш гнучким , ніж , так як ви можете робити копії частин масиву.

copyOf()System.arrayCopy()clone()


5
Arrays.copyOf () також виділяє пам’ять. у вашому прикладі, якщо ви змінюєте String [] target = new String [4]; а потім target = Arrays.copyOf () створює нову ціль, яка є рядком [3]. Не поведінка мемкопії.
MikeF

Arrays.copyOf внутрішньо використовує System.arraycopy, який є власним методом.
Gajraj Tanwar,

10

Якщо ви просто хочете отримати точну копію одновимірного масиву, використовуйте clone().

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

Для інших операцій копіювання масиву використовуйте System.arrayCopy/ Arrays.copyOfяк пропонує Том .

Загалом, cloneслід уникати, але це виняток із правила.


Див. Також докладніше у прийнятій відповіді на stackoverflow.com/questions/3208899/… .
Енді Томас

5

Ви можете використовувати System.arrayCopy . Він копіює елементи з вихідного масиву в масив призначення. Реалізація Sun використовує оптимізований вручну асемблер, тому це швидко.


3

Java насправді має щось подібне до memcpy (). Клас Unsafe має метод copyMemory (), який по суті ідентичний memcpy (). Звичайно, як і memcpy (), він не забезпечує захисту від накладання пам’яті, знищення даних тощо. Незрозуміло, чи це справді memcpy () чи memmove (). Його можна використовувати для копіювання з фактичних адрес на фактичні адреси або з посилань на посилання. Зверніть увагу, що якщо використовуються посилання, ви повинні надати зсув (інакше JVM загине якомога швидше).

Працює Unsafe.copyMemory () (до 2 Гб на секунду на моєму старому втомленому ПК). Використовуйте на власний ризик. Зауважте, що небезпечний клас існує не для всіх реалізацій JVM.


вибачте за те, що я пішов усім домашнім тваринам-сематаріям за цією давньою ниткою, але не могли б ви дати мені приклад, як це зробити за допомогою масиву посилань. І це швидше для невеликих обсягів даних (наприклад, 1-4 МБ) або просто гідне у випадку більших даних, таких як 2 Гб, про які ви згадали?
FinnTheHuman

2
Використання sun.misc.Unsafeкласу вважається поганою практикою "зламати" b / c, це приватний пакетний клас. Крім того, починаючи з Java 9, він більше не буде доступним, тому спроба використовувати цей клас - це те саме, що благати, щоб ваш код несподівано зламався.
code_dredd


2

Коли ви використовуєте JDK 1.5+, вам слід використовувати

System.arraycopy()

Замість

Arrays.copyOfRange()

Beacuse Arrays.copyOfRange () не був доданий до JDK 1.6. Отже, ви можете отримати

Java - “Cannot Find Symbol” error

при виклику Arrays.copyOfRange у цій версії JDK.


0

Використовуйте byteBufferViewVarHandle або byteArrayViewVarHandle.

Це дозволить вам скопіювати масив "longs" безпосередньо в масив "double" і тому подібне, наприклад:

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

Це дозволить вам зробити хакерство на зразок:

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

0

Ні. Java не має еквівалента memcpy. Java має еквівалент memmoveзамість цього.

Якщо аргументи src і dest посилаються на один і той же об'єкт масиву, то копіювання виконується так, ніби компоненти в позиціях srcPos через srcPos + length-1 спочатку скопіювали у тимчасовий масив із компонентами length, а потім вміст тимчасового масиву було скопійовано в позиції destPos через destPos + довжина-1 масиву призначення.

Документи Oracle

Дуже ймовірно System.arraycopy, ніколи не буде однакової продуктивності, як memcpyніби, srcі буде destпосилатися на один і той же масив. Зазвичай це буде досить швидко.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.