深拷贝浅拷贝

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


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

故名思议就是跟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@7150bd4d
test.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@6bbc4459
test.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@152b6651
test.Material@544a5ab2
49
49

材料类(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@5d888759
test.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@152b6651
test.Material@544a5ab2
test.Metal@5d888759
test.Metal@2e6e1408


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

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

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

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


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

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



反正我也不会改。







评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值