Java实现对象的深拷贝

1.浅拷贝的介绍

  • 1)对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
    2)对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
    3)浅拷贝是使用默认的 clone()方法来实现
    我们来看下面这个例子
    新建一个人类,里面有基本数据类型属性name,sex,age和引用数据类型属性friend
public class Person implements Cloneable, {
    private String name;
    private String sex;
    private Integer age;
    public Person friend;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public Object clone() {
        Person person= null;
        try {
            person = (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return person;
    }

测试类

public class NormalClone {
    public static void main(String[] args) {
        Person p=new Person();
        p.setName("mike");
        p.setAge(20);
        p.setSex("男");
        Person friend=new Person();
        friend.setName("jeffery");
        friend.setAge(19);
        friend.setSex("男");
        p.friend=friend;
        Person p2= (Person)p.clone();
        //发现p和p2的friend的hashcode一样,则两个朋友是同一个对象
        System.out.println(p.friend.hashCode());
        System.out.println(p2.friend.hashCode());
        System.out.println("=================");
        //改变p的friend的年龄
        friend.setAge(21);
        //改变p的年龄
        p.setAge(22);
        //p2的年龄没有变
        System.out.println(p);
        System.out.println(p2);
        //改变p的friend的年龄,p2的friend的值也变了
        System.out.println(p.friend+","+p2.friend);
    }
}

结果如下:
在这里插入图片描述
我们可以看到改变p的friend的年龄,p2的friend的值也变了,改变p的年龄,p2的年龄没有改变。
可以的出结论:
clone方法默认是使用的浅拷贝

2. 深拷贝的介绍

  • 1)复制对象的所有基本数据类型的成员变量值
    2)为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝
    3)深拷贝实现方式 1:重写 clone 方法来实现深拷贝
    4)深拷贝实现方式 2:通过对象序列化实现深拷贝(推荐)

代码实现1:通过重写clone方法

public class Person implements Cloneable, Serializable {
    private static final long serialVersionUID = -3943427356942430084L;
    /**
     姓名

    */
    private String name;
    private String sex;
    private Integer age;
    public Person friend;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public Object clone() {
        Person person= null;
        try {
            person = (Person) super.clone();
            if(person.friend!=null) {
                person.friend = (Person) friend.clone();
            }
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return person;
    }
}

结果如下:
在这里插入图片描述可以看出:改变p的朋友的年龄,p2的朋友年龄没有改变,这种方式实现深拷贝是可行的。
但是这样实现有一个问题,假如属性有很多个引用类型,以下这段代码要写很多段。

 if(person.friend!=null) {
  	person.friend = (Person) friend.clone();
  }

代码实现2:通过对线的序列化实现(推荐使用这种)**
Person类

public class Person implements Serializable {
    private static final long serialVersionUID = -3943427356942430084L;
    /**
     姓名

    */
    private String name;
    private String sex;
    private Integer age;
    public Person friend;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }

   public Object deepClone(){
        ByteArrayInputStream bis=null;
        ObjectInputStream ois=null;
        ByteArrayOutputStream bos=null;
        ObjectOutputStream oos=null;
       try {
           //序列化
           bos=new ByteArrayOutputStream();
           ObjectOutputStream objectOutputStream = oos = new ObjectOutputStream(bos);
           oos.writeObject(this);
           //反序列化
           bis=new ByteArrayInputStream(bos.toByteArray());
           ois=new ObjectInputStream(bis);
           Person p= (Person) ois.readObject();
           return p;
       } catch (IOException e) {
           e.printStackTrace();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } finally {
           try {
               bos.close();
               oos.close();
               bis.close();
               ois.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       return null;
   }
}

测试类

public class DeepClone {
    public static void main(String[] args) {
        Person p=new Person();
        p.setName("mike");
        p.setAge(20);
        p.setSex("男");
        Person friend=new Person();
        friend.setName("jeffery");
        friend.setAge(19);
        friend.setSex("男");
        p.friend=friend;
        Person p2= (Person)p.deepClone();
        //发现p和p2的friend的hashcode不一样,则两个朋友不是同一个对象
        System.out.println(p.friend.hashCode());
        System.out.println(p2.friend.hashCode());
        System.out.println("=================");
        //改变p的friend的年龄
        friend.setAge(21);
        //改变p的年龄
        p.setAge(22);
        //p2的年龄没有变
        System.out.println(p);
        System.out.println(p2);
        //改变p的friend的年龄,p2的friend的值没有变
        System.out.println(p.friend+","+p2.friend);
    }
}

结果如下:
在这里插入图片描述
这种方式也实现了深拷贝,而且不管有多少个引用类型的属性,代码不会变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值