Что более эффективно: System.arraycopy или Arrays.copyOf?

toArray метод в ArrayList, Блоховское использование оба System.arraycopy и 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;
}

Как я могу сравнить эти два метода копии и когда я должен использовать который?

72
задан 0xCursor 20 December 2018 в 06:57
поделиться

6 ответов

Разница в том, что 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;
}
98
ответ дан 24 November 2019 в 12:33
поделиться

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

12
ответ дан 24 November 2019 в 12:33
поделиться

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

3
ответ дан 24 November 2019 в 12:33
поделиться

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

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

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

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

Другой момент заключается в том, что Arrays.copyOf использует System.arraycopy под капотом. Следовательно, System.arraycopy is , на первый взгляд не должен быть медленнее 2 , чем Arrays.copyOf . Но вы можете видеть (из кода, процитированного выше ), что Arrays.copyOf в некоторых случаях будет использовать отражение для создания нового массива. Так что сравнение производительности непросто.

В этом анализе есть несколько недостатков.

  1. Мы смотрим на код реализации из конкретной версии Java. Эти методы могут измениться, что сделает недействительными предыдущие предположения об эффективности.

  2. Мы игнорируем возможность того, что JIT-компилятор может сделать какую-то хитроумную оптимизацию в особых случаях для этих методов. Очевидно, это действительно происходит с Arrays.copyOf ; см. Почему Arrays.copyOf в 2 раза быстрее, чем System.arraycopy для небольших массивов? .Этот метод является «внутренним» в реализациях Java текущего поколения, что означает, что JIT-компилятор будет игнорировать то, что находится в исходном коде Java!

Но в любом случае разница между двумя версиями составляет O (1) (т.е. не зависит от размера массива) и относительно небольшая. Поэтому я бы посоветовал использовать версию, которая делает ваш код наиболее легким для чтения, и беспокоиться только о том, какая из них быстрее, если профилирование говорит вам, что это важно.


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

34
ответ дан 24 November 2019 в 12:33
поделиться

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

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

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

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

13
ответ дан 24 November 2019 в 12:33
поделиться

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

 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 () внутри, поэтому производительность будет такой же.

11
ответ дан 24 November 2019 в 12:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: