Клонирование многомерных массивов

17
int[][] array = new int[][] {...}
int[][] clone = array.clone();

Я наивно ожидал, что это сработает. Но он этого не сделал - он клонировал только первое измерение, и мне пришлось идти и клонировать другое измерение вручную, если бы я хотел использовать настоящий клон. Примечание: содержимое было правильно скопировано. Но когда я изменил clone[0][1] , он отразился в array[0][1]

И хотя .clone() , как известно, выполняет мелкий клон, int[][] выглядит как один объект (если мы не знаем его внутренней реализации, по крайней мере)

Почему это поведение выбрано? Не int[][] ссылается на объект массива, а не только на первый размер массива? И в каких сценариях клонируется только первое измерение желаемого поведения?

    
задан Bozho 24.04.2013 в 09:37
источник

4 ответа

8
  

Почему выбрано это поведение?

Согласованность, скорее всего.

Как вы говорите, int[][] ссылается на объект массива. Так получилось, что содержимое каждого элемента массива представляет собой другой массив, но это всего лишь деталь. Java одинаково клонирует все массивы, и поскольку элементы могут быть любого типа, он не может гарантировать выполнение глубокой копии.

Следовательно, clone() для массивов выполняет мелкую копию, поэтому клонируется только первое измерение.

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

    
ответ дан Andrzej Doyle 24.04.2013 в 09:41
3

Это поведение показано, потому что нет истинного многомерного массива.

Java достигает нескольких измерений, создавая массивы массивов. Это означает:

int[][] is actually Array<Array<int>>

Следовательно, клон будет копировать только первое измерение.

Если вы пытаетесь с 3-мерным массивом, вам нужно будет клонировать три раза.

    
ответ дан Arjun Rao 24.04.2013 в 09:41
1

Метод clone является так называемой мелкой копией (см. другой ответ stackoverflow на метод clone ), что означает, что все элементы копируются по ссылке.

Чтобы получить то, что вы хотите (также называемое глубоким клонированием), вы можете либо скопировать каждый отдельный массив самостоятельно, используя Arrays.copy рекурсивно, поэтому каждый (под) массив, который вы найдете, получит глубокий клон или проверит этот ответ stackoverflow при глубоком клонировании .

Счастливый взлом: -)

    
ответ дан Jens Egholm 24.04.2013 в 09:43
1

Я действительно не могу воспроизвести описанное вами поведение. Я вижу некоторые ответы, в которых упоминается мелкая копия в качестве основной причины проблемы. Исправьте меня, если я ошибаюсь, мелкая копия просто означает, что вместо копирования объекта при клонировании мы получим копию ссылки. Хорошее объяснение можно найти здесь В Java, что такое мелкая копия?

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

int[][] array = new int[][] {{1,2,3},{4,5,6}, {7,8,9}};
int[][] clone = array.clone();

//Try this to see magic of shallow copy
//array[2][1]=11;

for(int i=0;i<array.length;i++)
    for(int j=0;j<array[i].length;j++)
        System.out.println("array["+i+"]["+j+"]"+array[i][j]);

for(int i=0;i<clone.length;i++)
    for(int j=0;j<clone[i].length;j++)
        System.out.println("clone["+i+"]["+j+"]"+clone[i][j]);

Для меня клонирование выполняется отлично, то есть оба массива имеют одинаковое содержимое. Единственная причина, по которой я могу думать о том, что проблема с клонированным массивом не будет отображать какую-либо информацию, заключается в том, что мы фактически модифицировали исходный массив после клонирования (тогда появляется неглубокая копия).

Кстати, я использовал Java 1.6, надеюсь, это не проблема.

Изменить: Если нам просто нужно понять, почему они представляют собой мелкую копию вместо глубокой копии многомерного массива. Давайте посмотрим на 2 факта.

  1. При клонировании объекты всегда клонируются как мелкая копия (копия ссылки объекта), только родные типы получают реальную копию. В Java, что такое мелкая копия?
  2. Массив в java фактически является объектом Является ли массив объектом в java

Теперь, комбинируя 1 и 2, мы знаем, что многомерный массив в Java является всего лишь объектом, который имеет ссылку на другие объекты массива.

Что-то вроде ArrayObj- & gt; {ArrayObj, ArrayObj, ArrayObj};

И поскольку у нас есть объекты внутри объектов (композиции), мы должны получить мелкую копию в соответствии с правилом клонирования Java.

    
ответ дан Kamal 24.04.2013 в 10:03
  • Я уточню. На самом деле клонирование происходит, но оно не глубокое. –  Bozho 24.04.2013 в 10:16