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

Производит ли Arrays.copyOf мелкую или глубокую копию?

Кажется, что существует много путаницы и разных мнений по этому поводу ([1] и другие источники) о том, будет ли Arrays.copyOf производить глубокую или мелкую копию.

Этот тест показывает, что копия глубокая:

String[] sourceArray = new String[] { "Foo" };
String[] targetArray = java.util.Arrays.copyOf( sourceArray, 1 );

sourceArray[0] = "Bar";

assertThat( targetArray[0] ).isEqualTo( "Foo" ); // passes

Этот тест показывает, что копия неглубокая:

String[][] sourceArray = new String[][] { new String[] { "Foo" } };
String[][] targetArray = java.util.Arrays.copyOf( sourceArray, 1 );

sourceArray[0][0] = "Bar";

assertThat( targetArray[0][0] ).isEqualTo( "Foo" ); // fails

Является ли решение просто тем, что выполняется глубокая копия измерения верхнего уровня, но другие измерения - это мелкая копия? Какова правда?

[1] Как сделать глубокую копию массива 2d в Java?

4b9b3361

Ответ 1

Создает мелкую копию, т.е. новый массив, содержащий "старые" ссылки (к тем же объектам, которые не копируются).

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

Этот тест показывает, что копия глубокая:

Нет, это не так. Когда вы назначаете новый объект в "исходный" массив, это не влияет на копию. Это, в конце концов, копия.

Это та же ситуация, что и:

String x = "foo";
String y = x;
x = "bar";

assertEquals(y, "foo");

Нет "глубокой копии" здесь.

Ответ 2

Форма Java Doc

.... два массива будут содержать одинаковые значения.

Поэтому в случае массива, содержащего ссылку, копируется только ссылка, а не фактический объект. Это означает мелкую копию.

Ответ 3

"Неглубокий" или "глубокий" - и это то, что я не вижу, чтобы кто-то точно определял - метод Arrays.copyOf(..) на практике создает копию исходного массива, которая остается незатронутой изменениями в исходном массиве.

Возьмем следующий простой пример с массивами int:

import java.util.Arrays;

public class DeepCopyTest
{

    public static void main(String[] args)
    {
       int[] source = { 1, 2, 3, 4, 5, 6};
       int[] target = new int[source.length];
       // Copy target from source via Arrays.copyOf(..) method :
       target = Arrays.copyOf(source, 6);
       // Check for equality :
       System.out.println("Source1 : " + Arrays.toString(source));
       System.out.println("Target1 : " + Arrays.toString(target));
       // Increment all entries in source array :
       for(int i = 0; i < source.length; i++)
       {
          source[i] = source[i] +1;
       }
       // See if target is affected :
       System.out.println("Source2 : " + Arrays.toString(source));
       System.out.println("Target2 : " + Arrays.toString(target));

    }

}

// OUTPUT
// ------
Source1 : [1, 2, 3, 4, 5, 6]
Target1 : [1, 2, 3, 4, 5, 6]
Source2 : [2, 3, 4, 5, 6, 7]
Target2 : [1, 2, 3, 4, 5, 6]

На практике, когда люди ищут "глубокую копию" массива, они просто хотят чего-то, что не зависит от изменений оригинала.

И этот метод Arrays.copyOf(..) `дает им это.

Так же, как и массивы примитивных типов, массивы объектов String также ведут себя как вышеприведенный пример, выводящий как:

Source1 : [a, b, c, d, e, f]
Target1 : [a, b, c, d, e, f]
Source2 : [a1, b1, c1, d1, e1, f1]
Target2 : [a, b, c, d, e, f]

когда начальные записи исходного массива конкатенируются с помощью "1".

Он также "работает" для массивов объектов в том смысле, что цель больше не привязана к источнику, когда последняя переназначается. НО смотря на выход для первого элемента обоих массивов после копирования, а затем после изменения источника [0] раскрывает полную правду:

Source1 : [email protected]
Target1 : [email protected]
Source2 : [email protected]
Target2 : [email protected]

После копирования исходного исходного массива целевые элементы просто указываются на любые значения, которые в настоящее время хранятся в их исходных копиях. Для целевого [0] это содержимое адреса памяти 1db9742, которое также является тем же самым источником памяти, что и источник [0].,.

И причина, по которой мы получаем прерывание между источником и целью после перенаправления источника [0], связана с тем, что оператор присваивания

source[0] = new Object();

просто приводит к тому, что ссылка на память, содержащаяся в источнике [0], должна быть изменена на какое-то новое местоположение, когда на нее указывает новый объект. Так что это не настоящая глубокая копия в чистом смысле, хотя во многих случаях она дает кодеру те же преимущества, что и глубокая копия.

С массивами примитивных данных метод Arrays.copyOf(..) не может копировать ссылки, поскольку они не используются для примитивов. Он просто копирует значения исходного элемента в целевые элементы. Снова мы имеем тот же эффект, что и глубокая копия за счет операции, которая требует гораздо меньше кода, чем для глубокой копии.

Итак, Arrays.copyOf(..) - это "дешевая" глубокая копия как для примитивных, так и для 1-D массивов объектов. Но любой массив данных более сложный и обнаруживается.

Возможно, его следует называть полу-глубокой копией.

Ответ 4

Он создает мелкую копию, потому что, поскольку java использует параметр по значению, копии всей переменной доступны в клонированном объекте, однако для ссылочного типа создается переменная копия адреса и указывает на тот же объект, который передается исходным массивом, поэтому при копировании объект изменен. Исходный объект в массиве также обновляется. см. код ниже.

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class ArraysCopyOfDemo
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Object[] originalArray= new Object[1];
        Employee e1= new Employee("Salman","Khan");
        originalArray[0]=e1;
        System.out.println("Original Array content printed ");
        printArray(originalArray);

      Object[] copiedArray=originalArray.clone();
        System.out.println("Copied Array content printed ");
        printArray(copiedArray);
        System.out.println("Copied Array content modified ");
        Employee CopiedEmp1= (Employee)copiedArray[0];
        CopiedEmp1.setFirstname("Amir");
        System.out.println("Copied Array content printed ");
        printArray(copiedArray);
        System.out.println("Original Array content printed to verify shallow copy or deep copy");
        printArray(originalArray);
    }
    private static void printArray(Object[] arrays ){
        for(Object emp:arrays){
            System.out.print(((Employee)emp).getFirstname() + " ");
            System.out.print(((Employee)emp).getLastname());
            System.out.println();
        }
    }
}
class Employee implements Cloneable{
    private String firstname;
    private String lastname;
    public Employee(String firstname,String lastname){
        this.firstname=firstname;
        this.lastname=lastname;
    }
    public String getFirstname(){
       return firstname;
    }
    public String getLastname(){
        return lastname;
    }
    public void setFirstname(String firstname){
        this.firstname=firstname;
    }
     public void setLirstname(String lastname){
         this.lastname=lastname;
    }

}

O/p
Original Array content printed 
Salman Khan
Copied Array content printed 
Salman Khan
Copied Array content modified 
Copied Array content printed 
Amir Khan
Original Array content printed to verify shallow copy or deep copy
Amir Khan

Ответ 5

Это глубокая копия. Он выглядит неглубоким в случае строк, потому что под обложками строки являются синглтонами. JVM имеет пул памяти для строк и делает только одну копию каждой уникальной строки. Поэтому вы всегда получаете копию ссылки на эту строку. В приведенном ниже примере показано, что для объекта класса выполняется глубокая копия. Когда исходный массив изменен, копия не изменяется.

открытый класс ArrayTest {

public static void main(String [] args) {
    Object [] objs = new Object[1];
    objs[0] = new Object();
    System.out.println("Original: " + objs[0].toString());

    Object [] copy = java.util.Arrays.copyOf(objs, 1);
    objs[0] = new Object();
    System.out.println("copy, after original reassigned: " +
    copy[0].toString());
    System.out.println("Original, after reassigned: " +
    objs[0].toString());
}

}