Java中的Clone()方法

对象克隆指的是创建对象的精确副本。它创建当前对象类的一个新实例,并使用该对象对应字段的内容初始化其所有字段。

null

使用赋值运算符创建 副本 参考变量

在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主页上,并帮助其他极客。

如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写评论

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享