深拷贝浅拷贝

来源:互联网 发布:规模经济 知乎 编辑:程序博客网 时间:2024/06/03 11:56

好久没写东西了,今天来聊聊深浅拷贝这两个东西。


深拷贝浅拷贝,其实我们也叫他深克隆浅克隆

故名思议就是跟Object基类的clone()有关。

我们先定义一下材料类:

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年12月11日 下午1:28:33  */public class Material {    private String id = "1";    public String getId() {        return id;    }}


接着来看看这段代码:

 

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年11月16日 下午1:44:30  */public class temp1 {        public static void main(String[] args) {                Material material = new Material();        Material materialTemp =  material;        System.out.println(material.toString() + "\n" + materialTemp.toString());    }    }

那么,待会出来的结果会是什么呢?相信你们也是知道的,打印了这两个对象实例的地址:

test.Material@7150bd4dtest.Material@7150bd4d

一样的,其实不难知道,这种操作只能是把两个引用引导到堆里面同一块地方


那么这么样才能"制造出长得一样的实例"呢?这是Object中的clone()就出现了。

要用clone()方法就必须继承Cloneable接口,那为什么clone()是在Object而不是在Cloneable下呢?

其实大家都知道,基本所有的类都基本默认继承了Object,同时clone也应该是所有类的一个基本属性,就写在了Object之下,

如果你没有接上Cloneable这个接口直接用clone()的话,会报CloneNotSupportedException这个异常,这个接口说实在的就是个标志,就是跟你说我是可以克隆的。


-------------------------扯远了----------------------------


那我们接上Cloneable看看

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年12月11日 下午1:28:33  */public class Material implements Cloneable{    private String id = "1";    public String getId() {        return id;    }        @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}

这里接上Cloneable同时还是重写Object的clone(),不然不给用。

然后我们再改我们的测试main:

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年11月16日 下午1:44:30  */public class temp1 {        public static void main(String[] args) {        Material material = new Material();        Material materialTemp = null;        try {            materialTemp = (Material) material.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        System.out.println(material.toString() + "\n" + materialTemp.toString());    }}

这个时候打印出来的是这样的:

test.Material@6bbc4459test.Material@152b6651
这样就实现了对象实例化的克隆。


那有人就问了:废话说得这么多,要讲深克隆浅克隆了吗?

这位兄弟,别急吗,我这就讲,你先把刀从我脖子移开行吗?

浅拷贝:

上面的基础例子我们知道了,那真就是拷贝完成了吗


那我们再来测试一下:

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年11月16日 下午1:44:30  */public class temp1 {        public static void main(String[] args) {        Material material = new Material();        Material materialTemp = null;        try {            materialTemp = (Material) material.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        System.out.println(material.toString() + "\n" + materialTemp.toString());        System.out.println(material.getId().hashCode() + "\n" + materialTemp.getId().hashCode()); //基本类型咱们用hashCode代替。    }}

那你觉得现在结果是怎么样的呢?

答案是这样的:

test.Material@152b6651test.Material@544a5ab24949

材料类(Material)确实是进行了克隆,但是,材料类的里面属性还是在内存的同一块地方啊

这就是浅拷贝了

浅拷贝就是只是克隆了表面而已,但是里面的对象实例内存的指向就还是一样,这个时候我们再来看看我们的深拷贝。


深拷贝:

我们在材料类再加个东西

我们先定义金属类(Metal)

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年12月12日 下午12:51:39  */public class Metal{    private String id;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }}
 然后在材料类中加上去这个金属类:

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年12月11日 下午1:28:33  */public class Material implements Cloneable{    private String id = "1";    private Metal metal = new Metal();    public String getId() {        return id;    }    public Metal getMetal(){        return metal;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}

这个时候打印这个
System.out.println(material.getMetal().toString() + "\n" + materialTemp.getMetal().toString());

结果肯定是一样的:

test.Metal@5d888759test.Metal@5d888759

深拷贝的主要点就在这了:

这个时候我们要先给金属类接上Cloneable并加上clone的属性

package test;/** * @author  lujw E-mail: lujw@toone.com.cn * @date 创建时间:2017年12月12日 下午12:51:39  */public class Metal implements Cloneable{    private String id;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}


然后重写材料类(Material)中的clone()方法:

    @Override    protected Object clone() throws CloneNotSupportedException {        Material newMaterial = (Material) super.clone();        newMaterial.metal = (Metal) metal.clone();        return newMaterial;    }
再次测试:

        System.out.println(material.toString() + "\n" + materialTemp.toString());        System.out.println(material.getMetal().toString() + "\n" + materialTemp.getMetal().toString());

结果是这样的:

test.Material@152b6651test.Material@544a5ab2test.Metal@5d888759test.Metal@2e6e1408


这样就是深拷贝了,是不是很简单。

当然,深拷贝这个东西是没有个绝对的,毕竟每个业务对象是不一样的,每个对象里面的属性是各不相同,

例子我刚刚的材料类(Material),里面有金属类(Metal),那金属类(Metal)之后还有可能是有黄金类(Gold)。。。

所以,复杂的业务往往比较难以全面考虑,全面考虑也是没什么用的,只要紧跟着业务走,就够了,没必要搞什么彻底深拷贝。


----------------------------------------分割线--------------------------------------------------

利用午休写的,写得烂有问题尽管在低下批评。



反正我也不会改。