Массивы ·
‹ Предыдущий Следующий ›
⏱ 5 минут чтения Обновлено: 2026-07-16

Метод System.arraycopy()

Метод System.arraycopy() копирует часть одного массива в другой массив (или в тот же самый) быстрее и надёжнее, чем ручной цикл for. Метод статический, объявлен в классе java.lang.System и реализован как native — то есть его тело написано не на Java, а на уровне JVM, что и даёт основной выигрыш в скорости.

Сигнатура и параметры метода

Метод имеет единственную сигнатуру и работает с массивами любого типа — примитивов и объектов:

public static native void arraycopy(Object src, int srcPos,
                                     Object dest, int destPos,
                                     int length)
Параметр Тип Значение
src Object (массив) Массив-источник, из которого копируются элементы
srcPos int Индекс, с которого начинается копирование в источнике
dest Object (массив) Массив-приёмник, в который копируются элементы
destPos int Индекс, с которого элементы записываются в приёмник
length int Количество копируемых элементов

Метод ничего не возвращает (void) и не создаёт новый массив — приёмник dest должен существовать и быть достаточно длинным ещё до вызова.

Пример: копирование части массива в другой массив

Рассмотрим пример, копирующий элементы 2, 3, 4 из массива arraySource в массив arrayDestination:

import java.util.Arrays;

public class ArrayCopyExample1 {
    public static void main(String[] args) {
        int[] arraySource = {1, 2, 3, 4, 5, 6};
        int[] arrayDestination = {0, 0, 0, 0, 0, 0, 0, 0};

        System.out.println("arraySource: " + Arrays.toString(arraySource));
        System.out.println("arrayDestination: "
                + Arrays.toString(arrayDestination));

        System.arraycopy(arraySource, 1, arrayDestination, 2, 3);
        System.out.println("arrayDestination after arrayCopy: "
                + Arrays.toString(arrayDestination));
    }
}

Результат выполнения:

arraySource: [1, 2, 3, 4, 5, 6]
arrayDestination: [0, 0, 0, 0, 0, 0, 0, 0]
arrayDestination after arrayCopy: [0, 0, 2, 3, 4, 0, 0, 0]

Вызов System.arraycopy(arraySource, 1, arrayDestination, 2, 3) означает: взять 3 элемента из arraySource, начиная с индекса 1 (это значения 2, 3, 4), и записать их в arrayDestination, начиная с индекса 2. Длины массивов при этом могут различаться — важно лишь, чтобы в обоих хватало места для указанного диапазона.

Копирование в тот же массив с перекрытием областей

Можно копировать в тот же массив, причём даже если исходный и целевой диапазоны перекрываются:

import java.util.Arrays;

public class ArrayCopyExample2 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7, 8};
        System.out.println(Arrays.toString(array));

        System.arraycopy(array, 1, array, 3, 3);
        System.out.println(Arrays.toString(array));
    }
}

Результат выполнения:

[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 2, 3, 4, 7, 8]

Важно

System.arraycopy() корректно обрабатывает перекрывающиеся диапазоны — элементы сначала как бы копируются во временную область, поэтому не перезатирают друг друга раньше времени. Наивный цикл for, копирующий элементы по одному в порядке возрастания индекса, на таком же перекрытии даст неверный результат: часть исходных значений будет затёрта ещё до того, как их успеют прочитать.

Исключения: когда arraycopy() выбрасывает ошибку

Метод не изменяет размеры массивов и не проверяет типы «на лету» так, как это делает обычный Java-код, поэтому часть проверок он выполняет сам и выбрасывает исключения:

Исключение Когда возникает
NullPointerException src или dest равны null
ArrayIndexOutOfBoundsException srcPos, destPos или length отрицательны, либо диапазон srcPos + length или destPos + length выходит за пределы соответствующего массива
ArrayStoreException элемент из src нельзя записать в dest из-за несовместимости типов (например, копирование Object[] с элементами String в Integer[])

Пример на ArrayIndexOutOfBoundsException — длина length больше, чем помещается в приёмник:

int[] src = {1, 2, 3};
int[] dest = new int[3];

try {
    System.arraycopy(src, 0, dest, 0, 5); // в dest нет места для 5 элементов
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Поймали: " + e.getMessage());
}

Пример на NullPointerException — приёмник не инициализирован:

int[] src = {1, 2, 3};
int[] dest = null;

try {
    System.arraycopy(src, 0, dest, 0, 3);
} catch (NullPointerException e) {
    System.out.println("dest равен null");
}

Важная деталь: если при копировании до возникновения исключения часть элементов уже была перенесена, эти изменения в dest останутся — метод не откатывает уже выполненную часть операции.

System.arraycopy() и другие способы копирования массива

Способ Создаёт новый массив? Особенности
System.arraycopy(...) Нет Копирует часть (или весь) массив в уже существующий приёмник, в том числе с перекрытием диапазонов
Arrays.copyOf(array, newLength) Да Создаёт новый массив нужной длины и копирует элементы; внутри использует System.arraycopy()
array.clone() Да Полная поверхностная копия массива той же длины и типа
Цикл for По ситуации Ручное поэлементное копирование: медленнее на больших массивах и легко ошибиться при перекрывающихся диапазонах

Выбирайте System.arraycopy(), когда приёмник уже есть и нужно скопировать в него только часть данных (или сдвинуть элементы внутри одного массива). Если же нужен именно новый массив — короче и понятнее использовать Arrays.copyOf() или clone(); оба они не отменяют arraycopy(), а построены поверх него.

Про сами массивы и работу с ними — в уроках «Одномерные массивы», «Многомерные массивы» и «Длина массива».

Производительность: почему arraycopy быстрее цикла

System.arraycopy() объявлен как native — JVM выполняет копирование напрямую в памяти (аналогично низкоуровневым операциям вроде memmove), минуя накладные расходы обычного байткода: проверку границ на каждой итерации, инкремент счётчика, вызовы. Именно поэтому этот метод — стандартный выбор внутри самой библиотеки классов Java: на нём построены Arrays.copyOf(), Arrays.copyOfRange() и внутренняя реализация многих коллекций.

На небольших массивах разница с ручным циклом незаметна, но на больших объёмах данных (десятки тысяч элементов и больше) System.arraycopy() и построенные на нём методы заметно быстрее и — благодаря корректной обработке перекрытий — надёжнее самодельного цикла.

Часто задаваемые вопросы

Что делает System.arraycopy()?

Копирует заданное количество элементов из одного массива в другой (или в тот же самый), начиная с указанных индексов источника и приёмника. Метод статический, находится в классе java.lang.System, ничего не возвращает и не создаёт новый массив — приёмник должен существовать заранее.

Какие исключения бросает System.arraycopy() и когда?

NullPointerException — если источник или приёмник равны null; ArrayIndexOutOfBoundsException — если индексы или длина отрицательны либо диапазон выходит за пределы массива; ArrayStoreException — если элементы источника несовместимы по типу с приёмником.

Чем System.arraycopy() отличается от Arrays.copyOf()?

System.arraycopy() копирует в уже существующий массив и может копировать только часть данных. Arrays.copyOf() удобнее, когда нужен именно новый массив: он сам создаёт массив нужной длины и внутри вызывает System.arraycopy().

Можно ли скопировать массив сам в себя?

Да, и это безопасно даже при перекрывающихся диапазонах индексов: System.arraycopy() обрабатывает такое копирование корректно, в отличие от наивного цикла for, который может затереть ещё не прочитанные элементы.

System.arraycopy() быстрее цикла for?

Как правило да, особенно на больших массивах: метод реализован как native и выполняет копирование на уровне JVM, минуя накладные расходы обычного байткода. На небольших массивах разница в производительности практически незаметна.

Презентация с видео на Patreon →

Видео объяснение

Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.

Комментарии

Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.