Подтвердить что ты не робот

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

Метод toArray в ArrayList, Bloch использует как System.arraycopy и Arrays.copyOf для копирования массива.

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a 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;
}

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

4b9b3361

Ответ 1

Разница в том, что 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;
}

Ответ 2

Хотя 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. Это значительно медленнее, чем простая C-style memcopy содержимого массива.

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

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

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

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

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


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

Ответ 3

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

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

Ответ 7

Если вы посмотрите на исходный код System.arraycopy() of и Array.copyOf(), для производительности.

System.arraycopy() - это код на C, он работает непосредственно с вашим массивом, не возвращает никаких значений и поэтому должен работать намного быстрее, чем Array.copyOf(). Тем не менее, если вам нужен новый массив для создания или если вам просто нужно значение операции копирования, вам нужно создать новый массив для этого, установить новую длину массива и т.д. Таким образом, вы не можете сделать возврат System.arraycopy (источник, 0, пункт назначения, 0, длина).

Тогда Array.copyOf() может создать для вас новый массив. Вы можете присвоить возвращаемое значение из Array.copyOf() для массива или вернуть его из метода, так как Array.copyOf() вернет вам значение вместо того, чтобы работать непосредственно с целевым массивом. Таким образом, ваш код будет выглядеть намного чище. Тем не менее, с точки зрения производительности, Array.copyOf() - это метод универсального типа, и он не знает заранее, с чем он будет работать. Таким образом, он должен вызвать Array.newInstance() или new Object(), а затем привести его к типу входного массива.

Итак, подведем итоги. Используйте System.arraycopy() из-за производительности. Используйте Array.copyOf() для более чистого кода.

Ответ 8

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

Ответ 9

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

byte [] копировать тест производительности

10 000 000 итераций 40b array.copyOfRange: 135ms systems.arraycopy: 141ms

10 000 000 итераций 1000b array.copyOfRange: 1861ms systems.arraycopy: 2211ms

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

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