← Назад к вопросам

Что такое клонирование двумерных массивов?

1.0 Junior🔥 31 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое клонирование двумерных массивов?

Клонирование двумерных массивов — это создание копии двумерного массива. Важность этого процесса в том, чтобы понимать разницу между поверхностным копированием (shallow copy) и глубоким копированием (deep copy).

Основная проблема

В Java массивы — это ссылочные типы. Когда вы копируете двумерный массив, нужно понимать, что копируется: сама структура или содержимое?

Двумерный массив:

array = [  [1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]  ]

Это массив ссылок на одномерные массивы
array[0] → ссылка на первый ряд
array[1] → ссылка на второй ряд
array[2] → ссылка на третий ряд

Проблема: Поверхностное копирование

❌ Плохо (Shallow Copy):

int[][] original = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// Простое присвоение
int[][] copy = original;  // ❌ Это НЕ копия!

// Это просто ещё одна ссылка на один и тот же массив
copy[0][0] = 999;

System.out.println(original[0][0]);  // 999 (изменился и оригинал!)
System.out.println(copy[0][0]);      // 999

// copy и original указывают на один объект

Использование clone() — тоже поверхностное копирование:

int[][] original = {
    {1, 2, 3},
    {4, 5, 6}
};

int[][] copy = original.clone();  // ← Только копирует ссылки на ряды!

// Массив copy скопирован, но он содержит ссылки
// на ТЕ ЖЕ одномерные массивы, что и original

copy[0][0] = 999;

System.out.println(original[0][0]);  // 999 (изменился оригинал!)
// Потому что copy[0] и original[0] указывают на один объект

Правильное копирование: Глубокое копирование

✅ Вариант 1: Вложенный clone()

int[][] original = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// Копируем каждый ряд
int[][] deepCopy = new int[original.length][];
for (int i = 0; i < original.length; i++) {
    deepCopy[i] = original[i].clone();  // Копируем каждый ряд
}

// Теперь это настоящая глубокая копия
deepCopy[0][0] = 999;

System.out.println(original[0][0]);  // 1 (не изменился)
System.out.println(deepCopy[0][0]);  // 999 (разные объекты)

✅ Вариант 2: Arrays.copyOf()

int[][] original = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

int[][] deepCopy = new int[original.length][];
for (int i = 0; i < original.length; i++) {
    deepCopy[i] = Arrays.copyOf(original[i], original[i].length);
}

deepCopy[0][0] = 999;
System.out.println(original[0][0]);  // 1 ✓

✅ Вариант 3: Ручное копирование

int[][] original = {
    {1, 2, 3},
    {4, 5, 6}
};

int[][] deepCopy = new int[original.length][original[0].length];

for (int i = 0; i < original.length; i++) {
    for (int j = 0; j < original[i].length; j++) {
        deepCopy[i][j] = original[i][j];
    }
}

deepCopy[0][0] = 999;
System.out.println(original[0][0]);  // 1 ✓

✅ Вариант 4: Использование Stream API (Java 8+)

int[][] original = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

int[][] deepCopy = Arrays.stream(original)
    .map(int[]::clone)  // Клонируем каждый ряд
    .toArray(int[][]::new);

deepCopy[0][0] = 999;
System.out.println(original[0][0]);  // 1 ✓

Сравнение методов

МетодТип копированияПроизводительностьПростота
Присвоение (=)Нет копииОчень быстро✓✓✓ но ❌ неправильно
clone()Shallow copyБыстро✓✓ но ❌ неполно
Цикл + clone()Deep copyСредне✓✓ хорошо
Ручное копированиеDeep copyМедленнее✓ но многовербально
Arrays.stream()Deep copyСредне✓✓✓ современно

Для объектов (не примитивов)

Проблема с объектами:

class Person {
    String name;
    Person(String name) { this.name = name; }
}

Person[][] original = {
    {new Person("Alice"), new Person("Bob")},
    {new Person("Charlie"), new Person("Dave")}
};

// Даже с clone() это shallow copy для объектов!
Person[][] copy = Arrays.stream(original)
    .map(int[]::clone)  // ← Копирует ссылки на Person объекты
    .toArray(Person[][]::new);

copy[0][0].name = "MODIFIED";

System.out.println(original[0][0].name);  // "MODIFIED" (один объект!)

✅ Правильно для объектов (полная глубокая копия):

Person[][] deepCopy = Arrays.stream(original)
    .map(row -> Arrays.stream(row)
        .map(person -> new Person(person.name))  // Новый объект
        .toArray(Person[]::new)
    )
    .toArray(Person[][]::new);

copy[0][0].name = "MODIFIED";

System.out.println(original[0][0].name);  // "Alice" (разные объекты)

Неправильные размеры (jagged arrays)

Jagged array (зубчатый массив):

// Разные размеры рядов
int[][] jagged = {
    {1, 2, 3, 4, 5},      // 5 элементов
    {6, 7},               // 2 элемента
    {8, 9, 10}            // 3 элемента
};

// Нельзя предположить размер [i][j]
// Правильное копирование:
int[][] deepCopy = new int[jagged.length][];
for (int i = 0; i < jagged.length; i++) {
    deepCopy[i] = jagged[i].clone();
}

Копирование с изменением размера

int[][] original = {
    {1, 2},
    {3, 4},
    {5, 6}
};

// Копирование только 2 рядов
int[][] copy = new int[2][];
for (int i = 0; i < 2; i++) {
    copy[i] = original[i].clone();
}

// Или через Arrays.copyOf
int[][] copy2 = Arrays.copyOf(original, 2);
for (int i = 0; i < copy2.length; i++) {
    copy2[i] = copy2[i].clone();  // Глубокая копия
}

Практические советы

1. Всегда используйте глубокое копирование для двумерных массивов

// ❌ Плохо
int[][] copy = original;      // Не копия
int[][] copy = original.clone();  // Shallow copy

// ✅ Хорошо
int[][] copy = Arrays.stream(original)
    .map(int[]::clone)
    .toArray(int[][]::new);

2. Проверяйте null значения

int[][] original = null;
int[][] copy = Arrays.stream(original)
    .map(int[]::clone)
    .toArray(int[][]::new);  // 💥 NullPointerException

// Правильно:
if (original != null) {
    int[][] copy = Arrays.stream(original)
        .map(int[]::clone)
        .toArray(int[][]::new);
}

3. Для больших массивов позаботьтесь о памяти

// Очень большой массив
int[][] huge = new int[10000][10000];

// Копирование займёт память и время
int[][] copy = Arrays.stream(huge)
    .map(int[]::clone)
    .toArray(int[][]::new);  // ~400 MB памяти

Заключение

Клонирование двумерных массивов требует понимания разницы между shallow и deep copy. Простой clone() или присвоение не подойдут — нужно копировать каждый ряд отдельно. Современный способ с Stream API самый читаемый и функциональный, но цикл с clone() тоже работает и более ясен для новичков.

Что такое клонирование двумерных массивов? | PrepBro