Arrays.copyOf: примеры (JAVA)
Arrays.copyOf(int[] original, int newLength): int[]Общее описание метода Arrays.copyOf
Метод Arrays.copyOf() из пакета java.util предоставляет удобный способ скопировать массив и одновременно изменить его длину. Выполняется поверхностное копирование элементов (shallow copy): для ссылочных типов копируются ссылки, а не сами объекты. При увеличении длины новые элементы инициализируются значениями по умолчанию: null для ссылочных типов и 0 / false для примитивов.
Доступные перегрузки (основные):
static- возвращает массив того же типа, что иT[] copyOf(T[] original, int newLength) original.static- создаёт массив заданного типаT[] copyOf(U[] original, int newLength, Class extends T[]> newType) newTypeи копирует элементы, выполняя проверку совместимости типов при присваивании.- Перегрузки для примитивов:
copyOf(byte[] , int),copyOf(int[] , int),copyOf(char[] , int)и т.д. для всех примитивных массивов.
Поведение по длине:
- Если
newLength == original.length, возвращается новый массив той же длины, содержащий копию элементов. - Если
newLength < original.length, элементы с индексами ≥ newLength отбрасываются (обрезка). - Если
newLength > original.length, в конец добавляются значения по умолчанию (null или 0/false).
Возвращаемое значение: новый массив указанной длины; исходный массив не изменяется.
Типичные исключения:
NullPointerException- еслиoriginalравенnull.NegativeArraySizeException- еслиnewLengthотрицателен.ArrayStoreException- при использовании перегрузки сnewType, если элементы не могут быть размещены в массиве запрошенного типа.
Реализация обычно использует System.arraycopy, поэтому сложность копирования линейна по числу копируемых элементов. Метод удобен для быстрого изменения длины массивов и для приведения массивов к требуемому типу (при соблюдении совместимости типов).
Короткие примеры использования
1. Простое расширение и усечение примитивного массива:
import java.util.Arrays;
class Demo1 {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = Arrays.copyOf(a, 5); // расширение
int[] c = Arrays.copyOf(a, 2); // усечение
System.out.println(Arrays.toString(b));
System.out.println(Arrays.toString(c));
}
}
[1, 2, 3, 0, 0] [1, 2]
2. Для ссылочных типов добавляются null:
import java.util.Arrays;
class Demo2 {
public static void main(String[] args) {
Integer[] src = {10, 20};
Integer[] dst = Arrays.copyOf(src, 4);
System.out.println(Arrays.toString(dst));
}
}
[10, 20, null, null]
3. Перегрузка с указанием типа массива (приведение типа массива):
import java.util.Arrays;
class Demo3 {
public static void main(String[] args) {
Object[] objs = {"a", "b"};
String[] strs = Arrays.copyOf(objs, objs.length, String[].class);
System.out.println(Arrays.toString(strs));
}
}
[a, b]
4. Попытка преобразовать несовместимые элементы приведёт к исключению:
import java.util.Arrays;
class Demo4 {
public static void main(String[] args) {
Object[] mixed = {"a", 1};
// следующая строка при выполнении вызовет ArrayStoreException
String[] strs = Arrays.copyOf(mixed, mixed.length, String[].class);
}
}
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer
at java.base/java.lang.System.arraycopy(Native Method)
...
5. Отрицательная длина вызывает исключение:
import java.util.Arrays;
class Demo5 { public static void main(String[] a) { int[] x = {1}; Arrays.copyOf(x, -1); } }
Exception in thread "main" java.lang.NegativeArraySizeException
at java.base/java.util.Arrays.copyOf(Arrays.java:...)
...Похожие методы в Java и особенности
Arrays.copyOfRange(original, from, to)- копирует указанный диапазон. Удобнее при извлечении подмассива.System.arraycopy(src, srcPos, dest, destPos, length)- низкоуровневый, быстрый, даёт контроль позиций, но требует заранее созданного массива назначения.array.clone()- создаёт копию всего массива того же типа и длины; не позволяет изменить длину прямо.- Коллекции:
ArrayListи другие коллекции удобнее при динамическом изменении размера; массивы остаются предпочтительны для примитивов и при необходимости максимальной производительности. - Streams (например,
Stream.toArray()) - удобны для преобразований, но могут быть медленнее и требуют дополнительных шагов для управления длиной и типом.
Рекомендуется выбирать:
Arrays.copyOf- при простом изменении длины или быстром приведении массива к виду нужного типа.System.arraycopy- при копировании частей массивов с контролем смещений и высокой производительности.ArrayList- при частых операциях вставки/удаления элементов.
Аналоги в других языках и их отличия
Краткие эквиваленты поведения (копирование + изменение длины):
- JavaScript:
slice()иconcat(). Для массивов JS расширение добавлениемundefined. Пример:
const a = [1,2,3];
const b = a.slice(0,2); // [1,2]
const c = a.concat([undefined, undefined]); // расширение до длины 5
b -> [1, 2] c -> [1, 2, 3, undefined, undefined]
- Python: срезы и операции с list. Удобно:
lst[:n]для усечения, для расширения - добавление элементов или использование+ [None]*(n-len).
a = [1,2,3]
b = a[:2]
c = a + [None]*(5-len(a))
print(b)
print(c)
[1, 2] [1, 2, 3, None, None]
- PHP:
array_slice()для усечения, для расширения - можно присоединить элементы или использоватьarray_pad().
$a = [1,2,3];
$b = array_slice($a, 0, 2);
$c = array_pad($a, 5, null);
var_export($b);
var_export($c);
array ( 0 => 1, 1 => 2, ) array ( 0 => 1, 1 => 2, 2 => 3, 3 => NULL, 4 => NULL, )
- C#:
Array.CopyиArray.Resize(ref array, newSize).Array.Resizeсоздаёт новый массив и присваивает ссылку переменной, поведение близко к Arrays.copyOf.
using System;
class X{ static void Main(){ int[] a = {1,2,3}; Array.Resize(ref a,5); Console.WriteLine(string.Join(", ", a));}}
1, 2, 3, 0, 0
- Go: встроенная функция
copy(dst, src)и создание слайса черезmake([]int, newLen). Для примитивов копируется значение, для ссылочных типов копируются ссылки.
package main
import ("fmt")
func main(){ a := []int{1,2,3}; b := make([]int,5); copy(b,a); fmt.Println(b) }
[1 2 3 0 0]
- Kotlin:
array.copyOf(newSize)(встроенная функция в Kotlin stdlib), поведение аналогично Java.
fun main(){ val a = arrayOf(1,2,3); val b = a.copyOf(5); println(b.joinToString()) }
1, 2, 3, null, null
Отличия от Java: многие языки используют динамические массивы/списки по умолчанию, поэтому операцию «копировать и изменить длину» чаще реализуют через встроенные операции со списками и срезами. Для статично типизированных языков (C#, Go) есть функции, близкие по семантике.
Типичные ошибки и их проявления
1. Ожидание глубокого копирования вместо поверхностного. Пример:
import java.util.Arrays;
class Err1 {
public static void main(String[] args) {
StringBuilder[] arr = {new StringBuilder("x")};
StringBuilder[] copy = Arrays.copyOf(arr, 1);
copy[0].append("y");
System.out.println(arr[0]);
}
}
xy
Пояснение: оба массива содержат ссылку на один и тот же объект.
2. Передача null в качестве original:
import java.util.Arrays;
class Err2 { public static void main(String[] args) { Arrays.copyOf(null, 3); } }
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:...)
...
3. Отрицательная длина:
int[] a = {1};
Arrays.copyOf(a, -5);
Exception in thread "main" java.lang.NegativeArraySizeException
at java.base/java.util.Arrays.copyOf(Arrays.java:...)
...
4. Ошибка приведения при использовании newType:
Object[] m = {"a", 2};
String[] s = Arrays.copyOf(m, m.length, String[].class);
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer
at java.base/java.lang.System.arraycopy(Native Method)
...
5. Ожидание автоматического расширения, как у коллекций. Arrays.copyOf создаёт новый массив, но не заменяет автоматически исходную ссылку, если это не сделать вручную.
Изменения и история метода
Методы Arrays.copyOf и Arrays.copyOfRange появились в Java SE 6 и сохраняют стабильный интерфейс в последующих версиях. Основные моменты:
- Новых значительных перегрузок после введения в JDK 6 не добавлялось; перегрузки для примитивов были частью первоначального набора.
- В более поздних релизах улучшений и оптимизаций реализации могло быть сделано, но семантика остаётся обратимо совместимой.
Для современных версий Java метод остаётся стандартным и рекомендуемым для быстрого изменения длины массива и создания копий.
Расширенные и нестандартные варианты применения
1. Реализация простого механизма динамического массива (похожего на ArrayList):
import java.util.Arrays;
class DynInt {
private int[] data = new int[2];
private int size = 0;
void add(int v){
if (size == data.length) data = Arrays.copyOf(data, data.length * 2);
data[size++] = v;
}
int get(int i){ return data[i]; }
public String toString(){ return Arrays.toString(Arrays.copyOf(data, size)); }
public static void main(String[] args){
DynInt d = new DynInt();
for(int i=0;i<5;i++) d.add(i);
System.out.println(d);
}
}
[0, 1, 2, 3, 4]
Пояснение: copyOf используется для удвоения ёмкости внутреннего массива при необходимости.
2. Копирование двумерного массива (внимание к поверхностному копированию):
import java.util.Arrays;
class TwoD {
public static void main(String[] args){
int[][] a = {{1,2},{3,4}};
int[][] b = Arrays.copyOf(a, a.length+1); // новый первый уровень, внутренние массивы те же
System.out.println(Arrays.deepToString(b));
b[0][0] = 9;
System.out.println(Arrays.deepToString(a));
}
}
[[1, 2], [3, 4], null] [[9, 2], [3, 4]]
Пояснение: внутренние массивы не клонируются автоматически; изменение одного отражается в другом.
3. Приведение типа массива при гарантии совместимости элементов (удобно при работе с API, возвращающими Object[]):
import java.util.Arrays;
class CastExample {
public static void main(String[] args){
Object[] objs = {"one","two"};
// если точно известно, что все элементы String
String[] s = Arrays.copyOf(objs, objs.length, String[].class);
for(String t : s) System.out.println(t.toUpperCase());
}
}
ONE TWO
4. Создание массива заданного типа с расширением и автозаполнением дефолтными значениями (использование в рефлексии/обобщениях):
import java.util.Arrays;
class ReflectCopy {
public static void main(String[] args){
Number[] nums = new Integer[] {1,2};
// создаётся массив типа Number[]; элементы присваиваются, если совместимы
Number[] n2 = Arrays.copyOf(nums, 4, Number[].class);
System.out.println(Arrays.toString(n2));
}
}
[1, 2, null, null]
5. Конкатенация массивов через копирование (эффективно для небольшого числа операций):
import java.util.Arrays;
class Concat {
static int[] concat(int[] a, int[] b){
int[] r = Arrays.copyOf(a, a.length + b.length);
System.arraycopy(b, 0, r, a.length, b.length);
return r;
}
public static void main(String[] args){
System.out.println(Arrays.toString(concat(new int[]{1,2}, new int[]{3,4})));
}
}
[1, 2, 3, 4]
Заключение: Arrays.copyOf удобен в оптимизированных потоках кода, где требуется быстро скопировать и изменить размер массива без набора вспомогательных конструкций.