刚才在总结原型设计模式的时候,觉得有必要把java的clone拿出来分析一下
想一想,为什么需要克隆?
为什么不重新new一个?道理很简单,目的是想要两个相同的对象,重新new一个还得自己重新赋值,太麻烦
如何克隆一个对象,初学者可能会这样写
这确实是做了克隆,但是是做了克隆引用,我们可以修改下student的值,看看cope拿到的值是什么
这个克隆的图示分析:我们希望的克隆是这样的
然而这个克隆的引用是这样的:
这样的话,改对象的值,这两个引用对象都会变,不是我们想要的结果
那我们来看下,java是怎样实现对象的克隆的
Object类中的clone
- 克隆对象和原对象不是同一个对象,占用不同的内存地址
- 克隆对象和原对象应该具有相同的类型,但它不是强制性的
- 克隆对象和原对象使用equals()方法比较应该是相等的,但它不是强制性的
- 因为每个类的基类都是Object,所以都有clone方法,但是它是protected,所以不能在类外访问 克隆一个对象,需要对clone重写
如何实现克隆(实现Cloneable接口,覆写clone方法)
- 浅克隆:原对象和克隆对象不同,但对象内的成员引用相同
- 深克隆:原对象和克隆对象不同,且对象内的成员引用不同
不逼逼,直接上代码:
可以看出来,这样克隆出来的对象地址是不一样的,其中一个对象里面的基本数据类型(还有String类型)的改变不影响另外一个对象的值,如果是包装类型的数据就不行了,乐意看下:
这是实现克隆接口,覆写clone的的代码:
这样的clone就是浅copy,把对象赋值一份,但是对象里面的对象却是复制的应用,想要都复制,就需要用深copy
深克隆
有两种实现方法
- 多层实现Cloneable类
- 利用序列化和反序列化
多层实现的Cloneable(就是把Bag这个类也实现Cloneable接口,覆写clone方法,然后在Student的clone方法里面执行Bag的clone方法)
总结:这样虽然也能解决,但是需要Bag类也实现接口,覆写方法,如果Bag类里面也有方法,还要覆写这一套,很麻烦,如果类的解构简单可以使用这种方法,复杂的话,可以使用序列化和反序列化实现深克隆
(需要Student和Bag实现序列化接口,student覆写clone方法)代码如下:
这种方法就是利用序列化对象后将其copy到流里面,而原对象仍在jvm中,然后从流中将其反序列化成另外一个对象到jvm中,从而实现深克隆