【Java】关于浅拷贝与深拷贝

主要是学习之后的一个梳理和总结。

clone的用法:

1.实现 Cloneable 接口。

2.重写clone()方法。

3.在方法中调用super.clone()。

稍微吐槽一下有些教学贴,一直在说重载clone()方法,也许是笔误,但我觉得还是要严谨,这里是重写。

深拷贝与浅拷贝:

浅拷贝:对基本数据类型进行值传递,对引用数据类型只是进行了引用的传递。

深拷贝:对基本数据类型进行值传递,对引用数据类型拷贝时创建了新对象,并复制其内的成员变量。

这里想多说一句,之前有看过说Java中只有值的传递,对于对象参数,值的内容是对象的引用。 

举个栗子:

我要实现一个Father类,一个Son类,通过具体的场景试图理解clone()的用法以及深拷贝和浅拷贝。

/**
 * @Author Max
 * @Date 2019/7/6 23:46
 **/
public class Father implements Cloneable {
    private String name;
    private int age;
    private Son son;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

   /* Getter and Setter */
}
/**
 * @Author Max
 * @Date 2019/7/6 23:46
 **/
public class Son implements Cloneable {
    private String name;
    private int age;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    /* Getter and Setter */

}

假设有一个叫Smith的35岁爸爸,有个10岁的儿子名叫Stan,Stan有个15岁的朋友,名叫Kim,Kim的爸爸和Stan的爸爸同名而且年纪还一样。于是就有了以下代码:

        Father father = new Father();
        father.setName("Smith");
        father.setAge(35);

        Son son = new Son();
        son.setName("Stan");
        son.setAge(10);

        father.setSon(son);

        Father father1 = (Father) father.clone();

        father1.getSon().setName("Kim");
        father1.getSon().setAge(15);
       
        System.out.println("father name: " + father.getName());
        System.out.println("father1 name: " + father1.getName());
        System.out.println("father age : " + father.getAge());
        System.out.println("father1 age : " + father1.getAge());
        
        System.out.println("father's son name: " + father.getSon().getName());
        System.out.println("father1's son name: " + father1.getSon().getName());
        System.out.println("father's son age : " + father.getSon().getAge());
        System.out.println("father1's son age :" + father1.getSon().getAge());

然后我们通过输出来看结果:

发现第一个Smith的儿子也变成Kim了,这是怎么回事呢?我们来看一下这两个Father对象是不是同一个对象,然后再看看这两个Son对象是不是同一个对象:

        System.out.println("== :" + (father == father1));
        System.out.println("equals() :" + father.equals(father1));
        System.out.println("father hashcode : " + father.hashCode());
        System.out.println("faher1 hashcode : " + father1.hashCode());

        System.out.println("=========================================");
        
        System.out.println("father's son hashcode: " + father.getSon().hashCode());
        System.out.println("father1's son hashcode: " + father1.getSon().hashCode() );

输出:

我们发现这两个father确实不是一个father了,但son却是一个son,这显然是不对的。

原来,我们在clone father的时候使用的是浅拷贝,它对于son对象没有创建一个新对象出来,所以会有问题。

那么该怎么办呢?深拷贝可以做这件事。

实际上,我们只需要在Father类的clone方法中显式地对son进行一次clone就可以了。

 @Override
    protected Object clone() throws CloneNotSupportedException {
        Father newFather = (Father) super.clone();
        newFather.setSon( (Son) this.son.clone());
        return newFather;
//        return super.clone();
    }

然后我们就可以发现,第二个father的son也是一个新创建的对象了:

所以,当你需要一个新的引用数据类型的时候,就使用深拷贝吧。如果这个例子改成,Kim和Stan是兄弟,即他们的爸爸是同一个人,那么可以使用浅拷贝。

Son类修改如下:

public class Son implements Cloneable {
    private String name;
    private int age;
    private Father father;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

Father类修改如下:

public class Father implements Cloneable {
    private String name;
    private int age;
//    private Son son;

    @Override
    protected Object clone() throws CloneNotSupportedException {
//        Father newFather = (Father) super.clone();
//        newFather.setSon( (Son) this.son.clone());
//        return newFather;
        return super.clone();
    }

测试:

        Father father = new Father();
        father.setName("Smith");
        father.setAge(35);

        Son son = new Son();
        son.setName("Stan");
        son.setAge(10);

        son.setFather(father);

        Son son2 = (Son) son.clone();
        son2.setName("Kim");
        son2.setAge(15);
       
        System.out.println("son hashcode:" + son.hashCode());
        System.out.println("son2 hashcode:" + son2.hashCode());

        System.out.println("=========================================");
        System.out.println("son name:" + son.getName());
        System.out.println("son2 name:" + son2.getName());
        System.out.println("son age:" + son.getAge());
        System.out.println("son2 age:" + son2.getAge());

        System.out.println("=========================================");
        System.out.println("Son's father hashcode:" + son.getFather().hashCode());
        System.out.println("Son2's father hashcode:" + son2.getFather().hashCode());
        System.out.println("son's father's name:" + son.getFather().getName());
        System.out.println("son2's father's name:" + son2.getFather().getName());

结果:

说了这么多,你一定和我一样理解了深拷贝和浅拷贝,以及clone()的用法了吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值