在继续克隆概念之前,让我们用对象创建概念刷新基础知识。 使用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