2010-04-07 6 views
59

Метод toArray в ArrayList, Bloch использует как System.arraycopy, так и Arrayys.copyOf для копирования массива.Что более эффективно: 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; 
} 

Как сравнить эти два метода копирования, когда их использовать?

+1

Что такое "Блох"? Почему это относится к фрагменту кода? –

+2

@ Циро Блох - это парень, который написал реализацию ArrayList. – Insomniac

+0

См. Также: https://stackoverflow.com/q/44487304/14955 – Thilo

ответ

86

Разница в том, что Arrays.copyOf не только копирует элементы, но и создает новый массив. System.arrayCopy копирует в существующий массив.

Здесь источник для Arrays.copyOf, так как вы можете видеть, что он использует System.arraycopy внутренне, чтобы заполнить новый массив.

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

Его очевидный .... Arrays.copyOf должен создать новый экземпляр массива, поскольку мы не передаем его; в то время как мы передаем пункт назначения System.arraycopy. Что касается скорости, снова, очевидно, System.arraycopy должен побеждать, поскольку это собственный метод, и в конечном итоге Arrays.copyOf также вызывает этот метод для копирования массива. –

+2

Источник Java [не имеет значения] (https://stackoverflow.com/questions/44487304/why-arrays-copyof-is-2-times-faster-than-system-arraycopy-for-small-arrays#comment75970318_44487304), так как была создана внутренняя. – maaartinus

11

System.arrayCopy намного быстрее. Он находится в системе, потому что он использует прямую копию памяти за пределами земли Java. Используйте его, когда это возможно.

+1

Но System.arraycopy только копирует в существующий массив. Arrays.copyOf также создает для вас выходной массив. – Thilo

+2

Это правда, и до тех пор, пока вы используете System.arraycopy под обложками, любая удобная обертка, которую вы используете, - это просто соус. –

+4

И есть случаи, когда 'System.arrayCopy' * не может * использовать прямую копию памяти. –

3

System.arrayCopy реализован изначально и, следовательно, будет быстрее, чем любой Java-код. Я рекомендую вам использовать его.

+4

Просто потому, что он использует собственный код через JNI, это не значит, что он будет быстрее: http://www.javaspecialists.eu/archive/Issue124.html – Dag

31

Хотя System.arraycopy реализована изначально, и, следовательно, может быть быстрее, чем цикл Java, это не всегда так быстро, как вы могли бы ожидать. Рассмотрим следующий пример:

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

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

В этом случае базовый тип foo и bar массивы имеют различные базовые типы, поэтому реализация arraycopy должен проверить тип каждой ссылки скопировали, чтобы убедиться, что это на самом деле ссылка на экземпляр String. Это значительно медленнее, чем простая mem-копия содержимого массива C-стиля.

Другое дело, что Arrays.copyOf использует System.arraycopy под капотом, так что экономия вы достичь путем создания нового массива и заполнения его самостоятельно, используя arraycopy будет минимальным. Предполагая, что это то, что вы пытаетесь сделать ...

Моей рекомендацией было бы использовать версию, которая сделает ваш код более легким для чтения, и только беспокоиться о том, какой из них быстрее, если профилирование говорит вам, что это имеет значение.


1 - Это может быть быстрее, но это также возможно, что JIT компилятор делает такую ​​хорошую работу по оптимизации цикла вручную кода, что нет никакой разницы.

+1

+1 для указания проверки типа, которая должна выполняться иногда. – Thilo

+0

@StephenC, Что касается вашего первого абзаца, есть случаи, когда 'System.arrayCopy' может быть на самом деле медленнее? – Pacerier

+0

@Pacerier - Я не знаю никого. Но это не невозможно. –

12

Если вы хотите точной копии массива (скажем, если вы хотите сделать защитную копию), наиболее эффективным способом скопировать массив, вероятно, используют clone() метод объекта массива:

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

Я не потрудился проверить его производительность, но у него есть хороший шанс быть довольно быстрым, так как он все родной (выделение и копирование при вызове), а клонирование - это своего рода специальный JVM блаженный способ копирования объектов (и это в основном зло для других целей) и, вероятно, сможет взять некоторые «ярлыки».

Лично я все равно использовал clone, если бы он был медленнее, чем любой другой способ копирования, потому что его легче читать и почти невозможно заглушить при записи. System.arrayCopy, с другой стороны ...

+1

Правильно, но 'System.arrayCopy' также является родным (и он посвящен этой задаче), в то время как' clone', похоже, приходится иметь дело со многими * условиями * ... – Pacerier

+0

@Pacerier «Я не часто использую' clone' ... но когда я это делаю, я использую его на массивах ». – gustafc

+0

Я говорил о * том * '.clone()' при использовании на массивах ....В любом случае он по-прежнему возвращает объект, который затем должен быть возвращен в массив (= дополнительная работа). – Pacerier

10

Вы посмотрели на реализацию Sun Array.copyOf()?

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

Как можно видеть, он использует System.arraycopy() внутренне, так что производительность будет такой же.

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

Вместо обсуждения это настоящие результаты. Очевидно, что ваш выбор будет зависеть от того, сколько данных вы хотите скопировать.

байт [] копируют тест производительность

10000000 Итерации 40b array.copyOfRange: 135ms systems.arraycopy: 141ms

10000000 итераций 1000B array.copyOfRange: 1861ms systems.arraycopy: 2211ms

10 000 000 итераций 4000b array.copyOfRange: 6315ms systems.arraycopy: 5251ms

1000000 итераций 100,000b array.copyOfRange: 15,198ms systems.arraycopy: 14783ms

Смежные вопросы