对浅拷贝和深拷贝的理解------拷贝两个相互引用的对象

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对象. 图解:

对浅拷贝和深拷贝的理解------拷贝两个相互引用的对象_第1张图片

 

那如何对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引用依然引用到同一个对象上. 这也很符合浅拷贝的概念.

看一下图解:

对浅拷贝和深拷贝的理解------拷贝两个相互引用的对象_第2张图片

 

那么如何才能实现真正的深拷贝呢. (使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对象, 这次可以说是真正实现了"深拷贝".

图解如下:

对浅拷贝和深拷贝的理解------拷贝两个相互引用的对象_第3张图片

 

你可能感兴趣的:(对浅拷贝和深拷贝的理解------拷贝两个相互引用的对象)