欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深拷贝浅拷贝

程序员文章站 2024-01-03 15:48:52
...

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

深拷贝浅拷贝

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

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

我们先定义一下材料类:

package test;
/**
 * @author  lujw E-mail: aaa@qq.com
 * @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: aaa@qq.com
 * @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());
    }
    
}

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

aaa@qq.com
aaa@qq.com

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


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

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

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

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


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


那我们接上Cloneable看看

package test;
/**
 * @author  lujw E-mail: aaa@qq.com
 * @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: aaa@qq.com
 * @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());
    }
}

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

aaa@qq.com
aaa@qq.com
这样就实现了对象实例化的克隆。


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

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

浅拷贝:

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


那我们再来测试一下:

package test;

/**
 * @author  lujw E-mail: aaa@qq.com
 * @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代替。
    }
}

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

答案是这样的:

aaa@qq.com
aaa@qq.com
49
49

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

这就是浅拷贝了

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


深拷贝:

我们在材料类再加个东西

我们先定义金属类(Metal)

package test;
/**
 * @author  lujw E-mail: aaa@qq.com
 * @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: aaa@qq.com
 * @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());

结果肯定是一样的:

aaa@qq.com
aaa@qq.com

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

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

package test;
/**
 * @author  lujw E-mail: aaa@qq.com
 * @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());

结果是这样的:

aaa@qq.com
aaa@qq.com
aaa@qq.com
aaa@qq.com


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

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

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

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


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

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



反正我也不会改。

深拷贝浅拷贝






上一篇:

下一篇: