对象克隆指的是创建对象的精确副本。它创建当前对象类的一个新实例,并使用该对象对应字段的内容初始化其所有字段。
使用赋值运算符创建 副本 参考变量
在Java中,没有操作符来创建对象的副本。与C++不同,在java中,如果使用赋值操作符,那么它将创建引用变量的副本而不是对象。这可以通过举一个例子来解释。下面的程序演示了同样的情况。
JAVA
// Java program to demonstrate that assignment operator // only creates a new reference to same object import java.io.*; // A test class whose objects are cloned class Test { int x, y; Test() { x = 10 ; y = 20 ; } } // Driver Class class Main { public static void main(String[] args) { Test ob1 = new Test(); System.out.println(ob1.x + " " + ob1.y); // Creating a new reference variable ob2 // pointing to same address as ob1 Test ob2 = ob1; // Any change made in ob2 will // be reflected in ob1 ob2.x = 100 ; System.out.println(ob1.x + " " + ob1.y); System.out.println(ob2.x + " " + ob2.y); } } |
10 20100 20100 20
使用clone()方法创建副本
要创建其对象副本的类中或其父类之一中必须有公共克隆方法。
- 实现clone()的每个类都应该调用super。clone()以获取克隆的对象引用。
- 该类还必须实现java。我们要创建其对象克隆的lang.Cloneable接口,否则在对该类的对象调用clone方法时,它将抛出CloneNotSupportedException。
- 语法:
protected Object clone() throws CloneNotSupportedException
clone()方法的用法-浅拷贝
请注意 –在下面的代码示例中,clone()方法确实使用不同的hashCode值创建了一个全新的对象,这意味着它位于一个单独的内存位置。但是由于测试对象c位于Test2内部,原语类型实现了深度复制,但是这个测试对象c仍然在t1和t2之间共享。为了克服这一点,我们显式地对对象变量c进行深度复制,这将在后面讨论。
JAVA
// A Java program to demonstrate // shallow copy using clone() import java.util.ArrayList; // An object reference of this class is // contained by Test2 class Test { int x, y; } // Contains a reference of Test and // implements clone with shallow copy. class Test2 implements Cloneable { int a; int b; Test c = new Test(); public Object clone() throws CloneNotSupportedException { return super .clone(); } } // Driver class public class Main { public static void main(String args[]) throws CloneNotSupportedException { Test2 t1 = new Test2(); t1.a = 10 ; t1.b = 20 ; t1.c.x = 30 ; t1.c.y = 40 ; Test2 t2 = (Test2)t1.clone(); // Creating a copy of object t1 // and passing it to t2 t2.a = 100 ; // Change in primitive type of t2 will // not be reflected in t1 field t2.c.x = 300 ; // Change in object type field will be // reflected in both t2 and t1(shallow copy) System.out.println(t1.a + " " + t1.b + " " + t1.c.x + " " + t1.c.y); System.out.println(t2.a + " " + t2.b + " " + t2.c.x + " " + t2.c.y); } } |
10 20 300 40100 20 300 40
在上面的例子中,t1。clone返回对象t1的浅拷贝。要获得对象的深度副本,必须在获得副本后对克隆方法进行某些修改。
深拷贝与浅拷贝
- 浅拷贝 是复制对象的方法,默认情况下在克隆中使用。在这种方法中,旧对象X的字段被复制到新对象Y。当复制对象类型字段时,引用被复制到Y,即对象Y将指向X指出的相同位置。如果字段值是基元类型,则复制基元类型的值。
- 因此,在对象X或Y的参照对象中所做的任何更改都将反映在其他对象中。
浅拷贝既便宜又容易制作。在上面的示例中,我们创建了 这个 对象
clone()方法的使用–深度复制
- 如果要创建对象X的深度副本并将其放置在新对象Y中,则会创建任何引用对象字段的新副本,并将这些引用放置在对象Y中。这意味着在对象X或Y的引用对象字段中所做的任何更改将仅反映在该对象中,而不会反映在另一个对象中。在下面的示例中,我们创建对象的深度副本。
- 深度副本复制所有字段,并复制字段指向的动态分配内存。当对象与其引用的对象一起复制时,会发生深度复制。
JAVA
// A Java program to demonstrate // deep copy using clone() // An object reference of this // class is contained by Test2 class Test { int x, y; } // Contains a reference of Test and // implements clone with deep copy. class Test2 implements Cloneable { int a, b; Test c = new Test(); public Object clone() throws CloneNotSupportedException { // Assign the shallow copy to // new reference variable t Test2 t = (Test2) super .clone(); // Creating a deep copy for c t.c = new Test(); t.c.x = c.x; t.c.y = c.y; // Create a new object for the field c // and assign it to shallow copy obtained, // to make it a deep copy return t; } } public class Main { public static void main(String args[]) throws CloneNotSupportedException { Test2 t1 = new Test2(); t1.a = 10 ; t1.b = 20 ; t1.c.x = 30 ; t1.c.y = 40 ; Test2 t3 = (Test2)t1.clone(); t3.a = 100 ; // Change in primitive type of t2 will // not be reflected in t1 field t3.c.x = 300 ; // Change in object type field of t2 will // not be reflected in t1(deep copy) System.out.println(t1.a + " " + t1.b + " " + t1.c.x + " " + t1.c.y); System.out.println(t3.a + " " + t3.b + " " + t3.c.x + " " + t3.c.y); } } |
10 20 30 40100 20 300 40
在上面的例子中,我们可以看到测试类的一个新对象被分配来复制一个将返回到clone方法的对象。因此,t3将获得对象t1的深度副本。因此,t3在“c”对象字段中所做的任何更改都不会反映在t1中。
克隆方法的优点:
- 如果我们使用赋值运算符将一个对象引用赋值给另一个引用变量,那么它将指向旧对象的相同地址位置,并且不会创建该对象的新副本。因此,参考变量中的任何更改都将反映在原始对象中。
- 如果我们使用复制构造函数,那么我们必须显式地复制所有数据,也就是说,我们必须显式地重新分配构造函数中类的所有字段。但在克隆方法中,创建新副本的工作是由该方法本身完成的。所以为了避免额外的处理,我们使用对象克隆。
本文由 安基特·阿加瓦尔。 如果你喜欢GeekSforgeks,并且想贡献自己的力量,你也可以写一篇文章,然后把你的文章邮寄给评论-team@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。
如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写评论