2种方法实现java对象的深拷贝
版权声明:本文为博主原创文章,遵循版权协议,转载请附上原文出处链接和本声明。
本文链接:
1、如果一个类没有实现Cloneable接口,直接调用clone()方法,会报异常CloneNotSupportedException,这一点已经在Object源码中写道:
- * @return a clone of this instance.
- * @exception CloneNotSupportedException if the object's class does not
- * support the {@code Cloneable} interface. Subclasses
- * that override the {@code clone} method can also
- * throw this exception to indicate that an instance cannot
- * be cloned.
- * @see java.lang.Cloneable
- */
- protected native Object clone() throws CloneNotSupportedException;
而且,源码也写到Object的clone()方法是浅拷贝的,这一点在之前的Object源码分析中我已经写过了.
2、自定义类实现深拷贝方法有2种,下面依次给出具体写法。
2.1、自定义类要实现Cloneable接口,并覆写clone()方法。
- /**
- * 深拷贝和浅拷贝的测试
- */
- //测试类1
- class Person implements Cloneable{
- String name;
- int age;
- Person(String name, int age){
- this.name=name;
- this.age=age;
- }
-
- public Object clone() {
- try{
- return super.clone();
- } catch(CloneNotSupportedException e){
- return null;
- }
- }
- }
- //测试类2
-
- class Animal implements Cloneable{
- Person host; //主人
- int age;//年纪
- Animal(Person person, int age){
- this.host=person;
- this.age=age;
- }
-
- public Object clone(){
- try{
- Animal animal=(Animal) super.clone();
- animal.host=(Person)host.clone(); //深拷贝处理
- return animal;
- } catch (CloneNotSupportedException e){
- return null;
- }
- }
- }
-
- //测试
- public class Main{
- public static void main(String[] args) {
- Person person1= new Person("cxh",26);
- Person person2=(Person)person1.clone();
- System.out.println( "----------------浅拷贝--------------");
- //测试Object的clone方法为浅拷贝
- //String类用==测试内存地址是否一致
- System.out.println( "person1和person2的name内存地址是否相同:"+(person1.name==person2.name));
-
-
-
- System.out.println( "----------------深拷贝--------------");
- //重写Object的clone方法,实现深拷贝
- //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝
- Animal animal1= new Animal(new Person("cxh",26),3);
- Animal animal2=(Animal) animal1.clone();
- System.out.println( "animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host));
- }
- }
- ----------------浅拷贝--------------
- person1和person2的name内存地址是否相同: true
- ----------------深拷贝--------------
- animal1和animal2的host内存地址是否相同: false
-
- Process finished with exit code 0
一个讲解很详细的博客:
2.2、通过序列化方式实现深拷贝:先将要拷贝对象写入到内存中的字节流中,然后再从这个字节流中读出刚刚存储的信息,作为一个新对象返回,那么这个新对象和原对象就不存在任何地址上的共享,自然实现了深拷贝。
自定义类需要实现Serializable接口。
- import java.io.*;
-
- /**
- * 深拷贝和浅拷贝的测试
- * 如何利用序列化来完成对象的拷贝呢?在内存中通过字节流的拷贝是比较容易实现的。把母对象写入到一个字节流中,再从字节流中将其读出来,
- * 这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的问题,真正实现对象的深拷贝。
- */
- //工具类
- class CloneUtil{
- public static <T extends Serializable> T clone(T obj){
- T cloneObj= null;
- try{
- //写入字节流
- ByteArrayOutputStream baos= new ByteArrayOutputStream();
- ObjectOutputStream oos= new ObjectOutputStream(baos);
- oos.writeObject(obj);
- oos.close();
-
- //分配内存,写入原始对象,生成新对象
- ByteArrayInputStream bais= new ByteArrayInputStream(baos.toByteArray());//获取上面的输出字节流
- ObjectInputStream ois= new ObjectInputStream(bais);
-
- //返回生成的新对象
- cloneObj=(T)ois.readObject();
- ois.close();
- } catch (Exception e){
- e.printStackTrace();
- }
- return cloneObj;
- }
- }
-
- //测试类1
- class Person implements Serializable{
- String name;
- int age;
- Person(String name, int age){
- this.name=name;
- this.age=age;
- }
-
- }
- //测试类2
-
- class Animal implements Serializable{
- Person host; //主人
- int age;//年纪
- Animal(Person person, int age){
- this.host=person;
- this.age=age;
- }
- }
-
-
- //测试
- public class Main{
- public static void main(String[] args) {
- System.out.println( "----------------深拷贝--------------");
- //重写Object的clone方法,实现深拷贝
- //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝
- Animal animal1= new Animal(new Person("cxh",26),3);
- Animal animal2=CloneUtil.clone(animal1);
- System.out.println( "animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host));
- }
- }
- ----------------深拷贝--------------
- animal1和animal2的host内存地址是否相同: false