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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

Я действительно не могу воспроизвести описанное вами поведение. Я вижу некоторые ответы, в которых упоминается мелкая копия в качестве основной причины проблемы. Исправьте меня, если я ошибаюсь, мелкая копия просто означает, что вместо копирования объекта при клонировании мы получим копию ссылки. Хорошее объяснение можно найти здесь В 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 и 2, мы знаем, что многомерный массив в Java является всего лишь объектом, который имеет ссылку на другие объекты массива.

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

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