博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
码农养成记3——关于Clone的深复制,还有浅复制
阅读量:6641 次
发布时间:2019-06-25

本文共 4124 字,大约阅读时间需要 13 分钟。

转载请标明地址 QuincySx:

今天闲来无事学了下原型模式,知道了clone 还有深复制还有浅复制,今天分享下:


先简单的说下clone, clone 实在 JVM 层进行的复制,他比 new 对象的速度要快得多,所以原型模式主要就是依赖的 clone ,

深复制 浅复制 的概念

  1. 浅复制(浅克隆)

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

  1. 深复制(深克隆)

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。


下面看一下 clone 的使用,直接看代码

public class Mall implements Cloneable {    private String name;    private ArrayList
shops=new ArrayList<>(); public Mall() { } public Mall(String name, ArrayList
shops) { this.name = name; this.shops = shops; } public String getName() { return name; } public void setName(String name) { this.name = name; } public ArrayList
getShops() { return shops; } public void addshop(String shop) { this.shops.add(shop); } @Override protected Mall clone() throws CloneNotSupportedException { Mall mall = null; if (mall == null) { mall = (Mall) super.clone(); } return mall; }}

随便建了个类,如果要实现 clone 要先实现 Cloneable 接口,然后重写 clone() 方法。我们先看一下浅复制

public static void main(String[] args) throws CloneNotSupportedException {        Mall mall=new Mall();        mall.setName("苹果");        Mall mall2 = mall.clone();        mall2.setName("西红柿");        System.out.println("mall name="+mall.getName());        System.out.println("mall2 name="+mall2.getName());    }
运行结果如下mall name=苹果mall2 name=西红柿

这个运行结果我想大家都能够想得到,我们再来看一个结果不太一样的浅复制

public static void main(String[] args) throws CloneNotSupportedException {        Mall mall=new Mall();        mall.addshop("苹果");        Mall mall2 = mall.clone();        mall2.addshop("西红柿");        System.out.println("mall shops="+mall.getShops());        System.out.println("mall2 shops="+mall2.getShops());    }
运行结果如下mall shops=[苹果, 西红柿]mall2 shops=[苹果, 西红柿]

现在发现了没有,浅复制的问题,原因是什么呢,原来在Java里面 clone 只是拷贝对象,对对象里面的引用对象只会拷贝他们的内存地址,其实指向的还是同一个引用,所以相当于 mall 对象 和 mall2 对象中的 shops 其实是共用的一个对象,这就导致了这个运行现象的发生。那么如何解决这个问题呢,其实使用深复制这个问题就可以迎刃而解,

在看一下深复制的例子

@Override    protected Mall clone() throws CloneNotSupportedException {        Mall mall = null;        if (mall == null) {            mall = (Mall) super.clone();            this.shops= (ArrayList
) this.shops.clone(); } return mall; }

最简单的深复制的做法就是把 mall 类的 clone() 改一下,看一下运行结果

mall shops=[苹果]mall2 shops=[苹果, 西红柿]

main() 方法没有发生任何改动,可以看到结果已经和预想一样了。

深复制的另一种写法(使用二进制流来复制对象)

先看一下 Mall 类

public class Mall implements Serializable{    private String name;    private ArrayList
shops=new ArrayList<>(); public Mall() { } public Mall(String name, ArrayList
shops) { this.name = name; this.shops = shops; } public String getName() { return name; } public void setName(String name) { this.name = name; } public ArrayList
getShops() { return shops; } public void addshop(String shop) { this.shops.add(shop); }}

可以看到这里把 实现的接口改为了 Serializable

重写的 clone() 方法也删除了

再看一下 main() 方法

public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {        Mall mall = new Mall();        mall.addshop("苹果");        Mall mall2 = (Mall) depthClone(mall);        mall2.addshop("西红柿");        System.out.println("mall shops=" + mall.getShops());        System.out.println("mall2 shops=" + mall2.getShops());    }    public static Object depthClone(Object srcObj) throws IOException, ClassNotFoundException {        Object cloneObj = null;        ByteArrayOutputStream out = new ByteArrayOutputStream();        ObjectOutputStream oo = new ObjectOutputStream(out);        oo.writeObject(srcObj);        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());        ObjectInputStream oi = new ObjectInputStream(in);        cloneObj = oi.readObject();        return cloneObj;    }

在这里加了一个 depthClone 方法

运行结果mall shops=[苹果]mall2 shops=[苹果, 西红柿]

可以看到运行结果与上面的深复制 输出结果无异


总结

这个小知识点也挺简单的,简单做个记录,至于两种深复制的方法大家可以自行选择

你可能感兴趣的文章
Solaris作业管理
查看>>
回顾2016,我的简单总结
查看>>
3372 选学霸
查看>>
ssh: connect to host localhost port 22: Connection refused 问题
查看>>
Adobe Photoshop CS或者CC卸载不了怎么办?
查看>>
怎样重置网络设置-出现打不开网站的时候可以用用
查看>>
【转】30岁之前打好基础,无惧职场“35岁现象”! | 人力资源心理学
查看>>
分布式搜索引擎Elasticsearch PHP类封装 使用原生api
查看>>
asp.net AJAX 定期刷新页面,然后,在 Timer 的事件中弹出窗口
查看>>
potrace源码分析一
查看>>
using eclipse to write c programe 0
查看>>
记录一下收集到的clojure相关的东东
查看>>
《Linux内核原理与分析》第七周作业
查看>>
浅析Xilinx 三速以太网MAC IP核(仿真篇)
查看>>
(转)Fidder教程
查看>>
UNREFERENCE_PARAMETER
查看>>
Linux -RAID
查看>>
OC中Foundation框架
查看>>
UIImageView
查看>>
spring boot&&cloud干货系列
查看>>