Статьи

Глубокое погружение в клонирование

Прежде чем мы продолжим концепцию клонирования, давайте освежим наши основы концепцией создания объекта. Когда объекты создаются с использованием оператора new, объекты получают выделение памяти в куче.

Создание объекта в куче

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

Glass objGlass1 = новое стекло ();

Стекло objGlass2 = objGlass1;

Здесь, в этом случае любые изменения, которые вы вносите в объект objGlass1, будут отражаться в объекте objGlass2 и наоборот. Это означает, что ‘ objGlass1 == objGlass2 ‘ вернет true, и ссылочные переменные objGlass1 и objGlass2 ссылаются на один и тот же объект. Однако, если вы намереваетесь скопировать объект, в отличие от простого копирования ссылки на объект, вам понадобится клонирование.

Что такое клонирование?

Клонирование — это процесс копирования объекта, то есть создания нового экземпляра путем копирования самого себя. Клонирование в Java может быть выполнено с помощью метода clone () объекта.

Клонирование создает и возвращает копию объекта с тем же классом и со всеми полями, имеющими одинаковые значения.

Glass objGlass1 = новое стекло ();

Glass objGlass2 = (Стекло) objGlass.clone ();

Давайте посмотрим на анализ ниже после клонирования:

  • objGlass1! = objGlass2 возвращает TRUE, что означает, что objGlass1 и objGlass2 ссылаются на две разные области памяти, т.е. на два разных объекта.
  • objGlass1.getClass () == objGlass2 .getClass () возвращает TRUE, что означает, что клонированный объект и исходный объект должны быть одного типа.
  • objGlass1.equals (objGlass2) возвращает TRUE, что означает, что данные клонированного объекта должны быть равны исходным (однако их можно изменить в любое время после клонирования).

Мелкое клонирование против глубокого клонирования

Java поддерживает два типа клонирования — мелкое клонирование и глубокое клонирование.

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

Мелкий клон копирует только структуру верхнего уровня объекта, а не нижние уровни.

Структура :

Мелкая структура клонирования

На приведенной выше диаграмме у OriginalObject1 есть Field1 и объект, который называется ReferenceObject1 . Теперь во время мелкого клонирования OriginalObject1 ClonedObject2 создается с Field2, имеющим скопированное значение из Field1, и оно все еще указывает на ReferenceObject1 . Причина этого в том, что Field1 имеет примитивный тип, поэтому его значения копируются в Field2 . Однако поскольку ReferenceObject1 является типом Object, ClonedObject2 указывает на тот же ReferenceObject1 .

Любые изменения, внесенные в ReferenceObject1, будут видны ClonedObject2 .

Мелкая структура клонирования

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

Глубокая структура клонирования

Как упомянуто на рисунке выше, у OriginalObject1 есть тип примитива Field1 и ReferenceObject1 . Теперь, когда мы выполняем глубокое клонирование OriginalObject1, ClonedObject2 создается вместе с Field2 , имеющим скопированные значения из Field1 и ReferenceObject2, содержащие скопированные значения ReferenceObject1 .

Глубокая структура клонирования

Пример мелкого клонирования:

Пример мелкого клонирования

Пример мелкого клонирования

В приведенном выше примере у нас есть оригинальный объект Employee, который имеет ссылку на класс Department и поле EmployeeName . Вначале предположим, что значения EmployeeName = «Chris» и DepartmentName = «Sales». Когда мы клонируем объект Employee с помощью Shallow Cloning, создается объект ClonedEmployee, в котором есть дублированное поле, клонированное EmployeeName и Department. Однако мы должны отметить, что дубликат объекта Department не создан. Клонированный объект Employee ссылается на тот же адрес памяти ссылочного класса Department.

Так что теперь, когда мы изменяем исходные значения объекта EmployeeName на «Peter», а DepartmentName на «Finance», клонированное поле EmployeeName не изменяется. Он по-прежнему содержит старое значение (согласно приведенному выше разделу диаграммы). Однако мы должны заметить, что клонированный DepartmentName теперь был изменен на «Финансы», чтобы отразить это изменение. Это связано с тем, что клонированный сотрудник ссылается на тот же адрес памяти, что и исходный объект. Таким образом, любые изменения, внесенные в исходную ссылку на объект, также видны клонированному объекту, ссылающемуся на исходный объект. Он не дублируется как поля.

Пример кода для мелкого клонирования

Department.java (ReferenceObject)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public class Department {
    private String deptName;
 
    public Department(String str) {
        deptName = str;
    }
 
    public String getDeptName() {
        return deptName;
    }
 
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
}

Employee.java (основной объект)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Employee implements Cloneable {
    private String employeeName;
    private Department dept;
 
    public String getEmployeeName() {
        return employeeName;
    }
 
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
 
    public Department getDept() {
        return dept;
    }
 
    public void setDept(Department dept) {
        this.dept = dept;
    }
 
    public Employee(String emp, String empDept) {
        employeeName = emp;
        dept = new Department(empDept);
    }
 
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Client.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {
        Employee emp = new Employee('Chris', 'Sales');
        System.out.println('Original Object value - Employee Name:'
                + emp.getEmployeeName() + ' & department name:'
                + emp.getDept().getDeptName());
        Employee clonedEmployee = (Employee) emp.clone();
        System.out.println('Cloned object value - Employee Name:'
                + clonedEmployee.getEmployeeName() + ' & department name:'
                + clonedEmployee.getDept().getDeptName());
        // Now let's change values of Original Object
        emp.setEmployeeName('Peter');
        emp.getDept().setDeptName('Finance');
        System.out
        .println('Original Object value after it is modified - Employee Name:'
                + emp.getEmployeeName()
                + ' & department name:'
                + emp.getDept().getDeptName());
        System.out
        .println('Cloned object value after modification of original object' +
                ' - Employee Name:'
                + clonedEmployee.getEmployeeName()
                + ' & department name:'
                + clonedEmployee.getDept().getDeptName());
    }

Пример глубокого клонирования

Пример глубокого клонирования

В случае глубокого клонирования, в отличие от мелкого клонирования, все поля исходного объекта копируются в объект клона, включая объект, на который ссылался исходный объект. Этот процесс создает копию динамически распределенной памяти, на которую указывают поля.

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

Пример кода для глубокого клонирования:

В случае глубокого клонирования единственное изменение происходит в методе clone () . В отличие от мелкого клонирования, метод super.clone () не вызывается, а объект создается с использованием оператора new внутри метода clone () .

1
2
3
4
5
public Object clone() {
    //Deep Copy process
        Employee e = new Employee(employeeName, dept.getDeptName());
        return e;
}

Надеюсь, вам понравилась эта статья. Пожалуйста, не стесняйтесь оставлять свои отзывы и комментарии.

Ссылка: Глубокое погружение в клонирование от нашего партнера JCG Майнака Госвами в блоге Idiotechie .