Java 方法
Java中的Clone()方法
对象克隆是指创建对象的精确副本。它创建当前对象类的新实例,并使用该对象相应字段的内容来初始化其所有字段。
使用Assignment操作符创建引用变量的副本
在Java中,没有操作员可以创建对象的副本。与C ++不同,在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 20
100 20
100 20
使用clone()方法创建副本
要创建对象副本的类必须在其中或其父类中的一个中具有公共克隆方法。
每个实现clone()的类都应该调用super.clone()来获取克隆的对象引用。
该类还必须实现其对象克隆我们要创建的java.lang.Cloneable接口,否则当在该类的对象上调用克隆方法时,它将抛出CloneNotSupportedException。
句法:
protected Object clone()抛出CloneNotSupportedException
clone()方法的用法 - 简单复制
// 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 40
100 20 300 40
在上面的例子中,t1.clone返回对象t1的浅表副本。要获得该对象的深层副本,必须在获得副本后在克隆方法中进行某些修改。
深拷贝vs浅拷贝
浅拷贝是复制对象的方法,在克隆中默认使用。在这种方法中,旧对象X的字段被复制到新对象Y.在复制对象类型字段时,引用被复制到Y,即对象Y将指向由X指出的相同位置。如果字段值为原始类型它复制原始类型的值。
因此,对象X或Y中的引用对象所做的任何更改都会反映到其他对象中。
浅拷贝价格便宜,制作简单。在上面的例子中,我们创建了一个对象的浅表副本。
clone()方法的用法 - Deep Copy
如果我们想创建对象X的深层副本并将其放置在新对象Y中,则创建任何引用对象字段的新副本,并将这些引用放置在对象Y中。这意味着对象X中的引用对象字段中所做的任何更改或者Y只会反映在那个对象中而不反映在另一个中。在下面的例子中,我们创建了对象的深层副本。
深层复制复制所有字段,并复制由这些字段指向的动态分配的内存。当对象与其引用的对象一起复制时,会发生深层复制。
// A Java program to demonstrate deep 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 deep copy.
class Test2 implements Cloneable
{
int a, b;
Test c = new Test();
public Object clone() throws
CloneNotSupportedException
{
// Assign the shallow copy to new refernce variable t
Test2 t = (Test2)super.clone();
t.c = new Test();
// 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 40
100 20 300 0
在上面的例子中,我们可以看到Test类的一个新对象已经被分配给将在克隆方法中返回的拷贝对象。由于t3将获得对象t1的深层拷贝。因此t3中'c'对象字段所做的任何更改都不会反映在t1中。
clone方法的优点:
如果我们使用赋值操作符将对象引用分配给另一个引用变量,则它将指向旧对象的相同地址位置,并且不会创建对象的新副本。由于这个参考变量的任何变化都会反映在原始对象中。
如果我们使用复制构造函数,那么我们必须明确地复制所有数据,即我们必须显式地在构造函数中重新分配类的所有字段。但是在克隆方法中,这个创建新副本的工作是由方法本身完成的。为了避免额外的处理,我们使用了对象克隆。