【Java】Cloneable接口的浅拷贝和深拷贝/克隆

clone克隆

Java中Object类中的clone方法可以创建一个对象的拷贝,

要调用clone方法,就要先实现Java内置的接口Cloneable

如:

class Name implements Cloneable{

    @Override    //重写clone方法
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

接下来看看克隆的简单应用:创建Goods类,表示货物,新建对象为book书

//定义Goods类,实现Cloneable接口
class Goods implements Cloneable{

    public double price = 19.9;

    @Override     //重写clone方法
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {

        Goods book1 = new Goods();           //创建新的Goods对象book1
        Goods book2 = (Goods) book1.clone(); //克隆book1,创建了拷贝,赋给book2

        System.out.println("book1 costs "+book1.price);
        System.out.println("book2 costs "+book2.price);

    }
}

在创建新对象后,通过调用clone进行了拷贝:

        Goods book1 = new Goods();           //创建新的Goods对象book1
        Goods book2 = (Goods) book1.clone(); //克隆book1,创建了拷贝,赋给book2

输出为:

 这里要注意,在调用clone方法时,clone是父类Object的方法,所以克隆得到的对象类型是Object类,再此要将克隆结果赋给book2的话,就要将对象的类型强制转换为Goods


浅拷贝

接下来我们再创建一个Storage类,代表书的数目,并在Goods中新建Storage的num对象

//新建类
class Storage {
    public int storage = 2;
}

class Goods implements Cloneable{

    public double price = 19.9;
    Storage num = new Storage();  //新建对象

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

}

 然后在拷贝后对book1的库存修改

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {

        Goods book1 = new Goods();
        Goods book2 = (Goods) book1.clone();  //拷贝

        System.out.println("book1 remains "+book1.num.storage);
        System.out.println("book2 remains "+book2.num.storage);
        System.out.println("===修改前的数据===");

        book1.num.storage = 4;   //修改book1数据

        System.out.println();
        System.out.println("book1 remains "+book1.num.storage);
        System.out.println("book2 remains "+book2.num.storage);
        System.out.println("===修改后的数据===");
    }

输出:

 可见,在如此拷贝的情况下,浅拷贝本体的数据修改后,拷贝副本的数据也会被修改。

其拷贝时的路径如下,先创建book1对象

 Goods book2 = (Goods) book1.clone();  //拷贝

 拷贝后:

 因为克隆的类是Goods,所以克隆之后,得到的新对象book2中的num依然是地址0x22中的数值

所以在修改book1.num.storage = 4后,0x22中的值被修改,book2中的也自然会被修改,这就是浅拷贝。


深拷贝

如要想在修改book1的时候,book2的数据不被修改,就要给类Storage也实现Cloneable接口

//实现Cloneable接口
class Storage implements Cloneable{
    public int storage = 2;

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

在拷贝Goods类的同时也实现Storage类num的拷贝,创建独立的拷贝对象:

class Goods implements Cloneable{

    public double price = 19.9;
    Storage num = new Storage();

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Goods tmp = (Goods) super.clone();    //创建新的拷贝赋给临时对象tmp
        tmp.num = (Storage)this.num.clone();  //同时将tmp的num进行拷贝
        return tmp;
    }

}

此时的对象直指向如图

然后进行数据修改

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {

        Goods book1 = new Goods();
        Goods book2 = (Goods) book1.clone();  //拷贝

        System.out.println("book1 remains "+book1.num.storage);
        System.out.println("book2 remains "+book2.num.storage);
        System.out.println("===修改前的数据===");

        book1.num.storage = 4;

        System.out.println();
        System.out.println("book1 remains "+book1.num.storage);
        System.out.println("book2 remains "+book2.num.storage);
        System.out.println("===修改后的数据===");
    }

运行结果:

 此时发现,在修改book1的数据后,book2的数据并没有被修改,这就是深拷贝。


总结: 

要实现深拷贝,就要将所用到的类都进行克隆,实现克隆本体和副本的独立。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值