在繼續克隆概念之前,讓我們用對象創建概念刷新基礎知識。 使用new運算符創建對象時,對象將在堆中獲取內存分配。
堆中的對象創建
在Java中,理想情況下僅通過引用變量修改對象,即僅復制對象的內存地址,因此原始對象中的任何更改都將反映在新變量中。
Glass objGlass1 = new Glass();
Glass 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支持兩種類型的克隆–淺克隆和深克隆。
如果是“ 淺”克隆,則會創建一個新對象,該對象具有原始對象中值的精確副本。 Object的clone()方法提供了淺層克隆。 在這種克隆機制中,將復制對象而不包含其包含的對象。
淺克隆僅復制對象的頂層結構,而不復制較低層。
結構形式
淺克隆結構
在上圖中, OriginalObject1具有Field1和一個包含的對象,稱為ReferenceObject1 。 現在,在淺克隆OriginalObject1的過程中,將使用具有從Field1復制的值的Field2創建ClonedObject2 ,它仍然指向ReferenceObject1 。 這背后的原因是Field1是原始類型,因此將其值復制到Field2中 。 但是,由于ReferenceObject1是對象類型,因此ClonedObject2指向相同的ReferenceObject1 。
對ReferenceObject1所做的任何更改都將可見ClonedObject2 。
淺克隆結構
如果是深度克隆 ,則復制所有字段。 在這種情況下,即使引用的對象也將與字段一起復制到克隆的對象中。
深克隆結構
如上圖所示, OriginalObject1具有基本類型Field1和ReferenceObject1 。 現在,當我們做OriginalObject1然后ClonedObject2與字段2是具有從Field 1和ReferenceObject2含有ReferenceObject1的復制值復制的值創建沿的深克隆。
深克隆結構
淺克隆示例:
淺克隆示例
淺克隆示例
在上面的示例中,我們有一個原始對象Employee,它引用了Department類和一個字段EmployeeName 。 首先,我們假設EmployeeName =“ Chris”和DepartmentName =“ Sales”的值。 當我們通過“淺層克隆”克隆對象Employee時,將創建一個ClonedEmployee對象,該對象具有一個復制字段EmployeeName和Department的重復字段。 但是,我們需要注意的是,沒有創建重復的Department對象。 克隆的Employee對象引用與所引用類Department相同的內存地址。
因此,現在當我們將EmployeeName的原始對象值更改為“ Peter”,將DepartmentName的原始對象值更改為“ Finance”時,克隆的EmployeeName字段將不會更改。 它仍然包含舊值(按照圖表的上述部分)。 但是,我們必須注意,克隆的DepartmentName現在已修改為“ Finance”以反映更改。 這是因為克隆的Employee引用與原始對象相同的內存地址。 因此,對原始對象引用所做的任何更改對于引用原始對象的克隆對象也是可見的。 它不會像字段一樣重復。
淺克隆的代碼示例
Department.java (ReferenceObject)
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 (主對象)
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;}}
}
客戶端程序
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 Objectemp.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()方法,而是使用clone()方法內部的new運算符創建對象。
public Object clone() {//Deep Copy processEmployee e = new Employee(employeeName, dept.getDeptName());return e;
}
希望您喜歡這篇文章。 請隨時提供您的反饋和意見。
參考:在Idiotechie博客上,我們的JCG合作伙伴 Mainak Goswami 深入探討了克隆 。
翻譯自: https://www.javacodegeeks.com/2012/11/deep-diving-into-cloning.html