面向对象编程中经常会遇到一个问题,就是对象的克隆。对于基本类型来说,可以用赋值运算符“=”来直接复制一份数据,但是对于对象来说,“=”只是将同一个对象的引用赋值给了变量,当这个对象改变时,所有引用了该对象的变量获取的值都会随之改变。
克隆对象的最简单一个方法是重新创建一个对象,然后将待克隆对象的每个成员属性的值都拷贝给新的对象的相应成员属性。但是,这种方法成本很高,尤其是当成员变量的类型是自定义的类时,这样做的代价是要写很多不必要的代码,而且很容易出错。
Java中提供了两种克隆方法——浅克隆和深克隆。
在浅克隆中,如果待克隆对象的成员属性是基础值类型,将复制一份给克隆对象;如果待克隆对象的成员属性是引用类型,则将该引用对象的地址复制一份给克隆对象,也就是说待克隆对象和克隆对象的成员属性都会指向相同的引用内存地址。
Java中浅克隆的实现方法为:先是类实现Cloneable接口(接口的概念将在下一节中介绍),然后重写Object.clone()方法。基础值类型浅克隆示例如下:
动手写9.5.5
其运行结果为:
图9.5.4 浅克隆示例①
自定义一个CatAction类,在Cat类中添加一个该自定义类的引用类型成员属性后,再来看代码的运行结果,修改后代码如下所示:
动手写9.5.6
上面示例中,复制catA到catB后,修改catB的行为,catA的行为也被更改了,都为“玩球球”,运行结果如下:
(www.xing528.com)
图9.5.5 浅克隆示例②
从上面示例可以看到,当成员属性是引用类型对象时,原来对象的该属性被更改,克隆对象的属性也会跟着改变,这不是克隆期望的结果。如果要实现对象的全部克隆,则需要使用深克隆。
在深克隆中,无论待克隆独享的成员属性是基础值类型还是引用类型,都将赋值一份给克隆对象,所有引用对象也都会重新克隆一份过去。修改Cat类和CatAction类的clone()方法,main()方法与动手写9.5.6保持一致,代码如下所示:
动手写9.5.7
其运行结果为:
图9.5.6 深克隆示例
如果对象的成员属性为引用类型,而这个类型中还包含很多引用类型,或者内层又嵌套包含引用类型,使用clone()方法将会很麻烦。Java中提供了序列化的方式来实现对象的深克隆,而要实现序列化的对象的类则必须实现Serializable接口。
动手写9.5.8
序列化是将对象转换成流的过程,通过序列化不仅可以复制对象本身,也可以复制其成员属性引用的对象。序列化的概念会在后面章节中进行详细介绍。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。