Object类的 clone() 方法能实现对对象的浅拷贝, 如果需要对对象实现深拷贝, 则需要实现Cloneable接口并重写 clone() 方法, 且方法访问权限为 public.
我们来看看当两个对象相互引用时, 实现浅拷贝和深拷贝的情况:
Man类中存在一个Woman引用类型的实例属性, Woman类中也存在一个 Man引用类型的实例属性. 使Man类实现 Cloneable接口并且重写clone() 方法, 对 Man对象进行浅拷贝, 来看看原对象的副本中的Woman引用变量到底引用的是什么.
创建Man类和Woman类
public class Man implements Cloneable{
private int m;
private Woman woman;
public int getM() {
return m;
}
public void setM(int m) {
this.m = m;
}
public Woman getWoman() {
return woman;
}
public void setWoman(Woman woman) {
this.woman = woman;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Woman {
private int w;
private Man man;
public int getW() {
return w;
}
public void setW(int w) {
this.w = w;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
}
下面是测试对Man对象进行浅拷贝:
public static void main(String[] args) throws CloneNotSupportedException {
//创建一个Man对象,并设置成员变量初始化值
Man man=new Man();
man.setM(10);
Woman woman=new Woman();
woman.setW(11);
man.setWoman(woman);//将Man对象中的引用变量指向w1对象
woman.setMan(man);//同理,将Woman对象中的引用变量指向m1对象
//对man对象实现浅拷贝
Man man2= (Man) man.clone();
System.out.println(man==man2);//输出false
System.out.println(man.getWoman()==man2.getWoman());//true
System.out.println(man.getWoman().getMan()==man2.getWoman().getMan());//true
System.out.println(man);//com.clonedemo.Man@66d3c617
System.out.println(man2.getWoman().getMan());//com.clonedemo.Man@66d3c617
}
}
由上面的代码可以看出, 对man对象进行浅拷贝, man2与man对象指向不同的对象. 并且引用类型woman指向同一个Woman对象woman. 这完全符合浅拷贝的概念. 还可以发现, 两个Man对象中的woman对象中的man引用类型指向的是同一个对象, 这个对象就是我们在程序中为 woman对象中的man引用初始化的 man对象. 图解:
那如何对Man对象实现深拷贝呢
我们先来看看重写Man中的clone() 方法并且Woman类也实现Cloneable接口实现重写clone()方法实现浅拷贝:
public class Man implements Cloneable{
private int m;
private Woman woman;
public int getM() {
return m;
}
public void setM(int m) {
this.m = m;
}
public Woman getWoman() {
return woman;
}
public void setWoman(Woman woman) {
this.woman = woman;
}
@Override
public Object clone() throws CloneNotSupportedException {
Man man2= (Man) super.clone();
man2.setWoman((Woman) woman.clone());
return man2;
}
}
public class Woman implements Cloneable{
private int w;
private Man man;
public int getW() {
return w;
}
public void setW(int w) {
this.w = w;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
进行拷贝测试:
@Test
public void test() throws CloneNotSupportedException {
Man man=new Man();
Woman woman=new Woman();
man.setWoman(woman);
woman.setMan(man);
//对man对象进行深拷贝
Man man2= (Man) man.clone();
System.out.println(man==man2);//false
System.out.println(man.getWoman()==man2.getWoman());//false
System.out.println(man.getWoman().getMan()==man2.getWoman().getMan());//true
System.out.println(man);//com.clonedemo.Man@1efed156
System.out.println(man2.getWoman().getMan());//com.clonedemo.Man@1efed156
}
我们可以看到, 现在原对象man和拷贝对象man2中的 woman引用指向不同的 Woman对象. 同时也发现两个Woman对象中的实例属性man引用依旧指向同一个Man对象. 也就是都引用到 man原对象上. 这是因为在 Woman的clone()方法中, 只是简单调用了Object类的clone() 方法, 实现的是对Woman对象的浅拷贝. 也就是说并没有对Woman对象中的man引用变量进行对象复制, 两个Woman对象中的 man引用依然引用到同一个对象上. 这也很符合浅拷贝的概念.
看一下图解:
那么如何才能实现真正的深拷贝呢. (使Man副本与Woman副本对象也相互引用)
我们再对Man类的clone()方法进行修改, 实现深拷贝. Woman类不做修改代码如下:
public class Man implements Cloneable{
private int m;
private Woman woman;
public int getM() {
return m;
}
public void setM(int m) {
this.m = m;
}
public Woman getWoman() {
return woman;
}
public void setWoman(Woman woman) {
this.woman = woman;
}
@Override
public Object clone() throws CloneNotSupportedException {
Man man2= (Man) super.clone();
Woman wClone= (Woman) woman.clone();
wClone.setMan(man2);
man2.setWoman(wClone);
return man2;
}
}
public class Woman implements Cloneable{
private int w;
private Man man;
public int getW() {
return w;
}
public void setW(int w) {
this.w = w;
}
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
再次进行测试:
@Test
public void test() throws CloneNotSupportedException {
Man man=new Man();
Woman woman=new Woman();
man.setWoman(woman);
woman.setMan(man);
//对man对象进行深拷贝
Man man2= (Man) man.clone();
System.out.println(man==man2);//false
System.out.println(man.getWoman()==man2.getWoman());//false
System.out.println(man.getWoman().getMan()==man2.getWoman().getMan());//false
System.out.println(man2.getWoman().getMan()==man2);//true
System.out.println(man);//com.clonedemo.Man@1efed156
System.out.println(man2);//com.clonedemo.Man@6737fd8f
System.out.println(man2.getWoman().getMan());//com.clonedemo.Man@6737fd8f
}
我们这次可以发现副本对象man2中的 woman引用的对象是一个独立的副本对象, 而且此副本对象中的man引用, 也引用的是man2对象, 这次可以说是真正实现了"深拷贝".
图解如下: