Object的clone()方法


Object的clone()方法

关于浅拷贝与深拷贝

有时我们在clone一些对象时,发现修改了克隆对象信息,原始对象信息有些部分却也发生了改变,这就是“浅拷贝”现象。
相对的,深拷贝就是克隆后的对象与原始对象不会相互影响。

下面看一个浅拷贝的案例:
创建一个Person类
Person.java
package com.eric.常用类.object.clone.浅拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 创建person观察浅拷贝的效果
 * @CreateTime 2020-11-27 12:27:20
 */
public class Person implements Cloneable{
    private String name;//名字
    private int age;//年龄
    private Box box;//包裹

    public Person(String name, int age, Box box) {
        this.name = name;
        this.age = age;
        this.box = box;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Box getBox() {
        return box;
    }

    public void setBox(Box box) {
        this.box = box;
    }

    public String disPlay() {
        return "Person[" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", box=" + box +
                ']';
    }
}
:Person类要实现Cloneable接口,并且重写Object的clone()方法。

同时创建Box(包裹)类
Box.java
package com.eric.常用类.object.clone.浅拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 装东西的包裹
 * @CreateTime 2020-11-27 12:30:01
 */
public class Box {
    private String sa;//物品A
    private String sb;//物品B

    public Box(String sa, String sb) {
        this.sa = sa;
        this.sb = sb;
    }

    public String getSa() {
        return sa;
    }

    public void setSa(String sa) {
        this.sa = sa;
    }

    public String getSb() {
        return sb;
    }

    public void setSb(String sb) {
        this.sb = sb;
    }

    @Override
    public String toString() {
        return "Box[" +
                "sa='" + sa + '\'' +
                ", sb='" + sb + '\'' +
                ']';
    }
}
注意:因为要演示浅拷贝,因此Person的toString()方法不能通过继承方式使用,这里改为了disPlay();

测试类
test.java
package com.eric.常用类.object.clone.浅拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 浅拷贝测试
 * @CreateTime 2020-11-27 12:32:49
 */
public class test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("Eric",22,new Box("时间控制器","免费抽奖机"));
        //克隆
        Person clone = (Person)person.clone();

        System.out.println(person);
        System.out.println(clone);

        System.out.println(person.disPlay());
        System.out.println(clone.disPlay());

        clone.setName("喵酱");
        clone.setAge(20);
        Box box = clone.getBox();
        box.setSa("空");
        System.out.println(clone.disPlay());
        System.out.println(person.disPlay());

    }
}

测试结果
com.eric.常用类.object.clone.Person@1540e19d
com.eric.常用类.object.clone.Person@677327b6
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
Person[name='喵酱', age=20, box=Box[sa='空', sb='免费抽奖机']]
Person[name='Eric', age=22, box=Box[sa='空', sb='免费抽奖机']]
结果分析
  • 从1,2行可以看出浅拷贝的克隆对象与原始对象已经是两个不同的对象。
  • 从3,4行可以看出克隆后的两个对象信息是相同的。
  • 修改克隆对象信息后,从5,6行发现,克隆对象(clone)与原始对象(person)中包含的对象信息(box)是共用的。即只克隆了对象引用

深拷贝
知道了浅拷贝就很容易引出深拷贝了,深拷贝就是将其中的对象也实现克隆,从而使得双方数据互不影响的效果。有两种实现方式:一种序列化实现,另一种所有的对象都实现clone()和接口。
【1】重写clone()方法实现
1.Box类实现Cloneable接口,同样Override这个clone()方法。
package com.eric.常用类.object.clone.深拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 装东西的包裹
 * @CreateTime 2020-11-27 12:30:01
 */
public class Box implements Cloneable{
    private String sa;//物品A
    private String sb;//物品B

    public Box(String sa, String sb) {
        this.sa = sa;
        this.sb = sb;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public String getSa() {
        return sa;
    }

    public void setSa(String sa) {
        this.sa = sa;
    }

    public String getSb() {
        return sb;
    }

    public void setSb(String sb) {
        this.sb = sb;
    }

    @Override
    public String toString() {
        return "Box[" +
                "sa='" + sa + '\'' +
                ", sb='" + sb + '\'' +
                ']';
    }
}
2.Person类的clone()方法做一下小改动。
package com.eric.常用类.object.clone.深拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 创建person观察浅拷贝的效果
 * @CreateTime 2020-11-27 12:27:20
 */
public class Person implements Cloneable{
    private String name;//名字
    private int age;//年龄
    private Box box;//包裹

    public Person(String name, int age, Box box) {
        this.name = name;
        this.age = age;
        this.box = box;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person personClone = (Person)super.clone();
        //将克隆的box(包裹)赋值给克隆person(人)
        personClone.box = (Box)box.clone();
        return personClone;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Box getBox() {
        return box;
    }

    public void setBox(Box box) {
        this.box = box;
    }

    public String disPlay() {
        return "Person[" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", box=" + box +
                ']';
    }
}
3.同样的测试。
package com.eric.常用类.object.clone.深拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 浅拷贝测试
 * @CreateTime 2020-11-27 12:32:49
 */
public class test {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("Eric",22,new Box("时间控制器","免费抽奖机"));
        //克隆
        Person clone = (Person)person.clone();

        System.out.println(person);
        System.out.println(clone);

        System.out.println(person.disPlay());
        System.out.println(clone.disPlay());

        clone.setName("喵酱");
        clone.setAge(20);
        Box box = clone.getBox();
        box.setSa("空");
        System.out.println(clone.disPlay());
        System.out.println(person.disPlay());

    }
}
4.测试结果
com.eric.常用类.object.clone.深拷贝.Person@1540e19d
com.eric.常用类.object.clone.深拷贝.Person@677327b6
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
Person[name='喵酱', age=20, box=Box[sa='空', sb='免费抽奖机']]
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
结果显而易见,克隆对象与原对象已经不会相互影响到了。
但细细想一下,就会发现,如果person中的对象属性非常多呢,并且person的对象中仍然存在对象。如果仍使用这种方法的会,会发现有些情况下需要写大量重复的或类似的代码。
这种方式只适用于引用变量比较少的时候。
下面介绍序列化方式实现深拷贝。

【2】序列化方式实现深拷贝
原理:将对象转换成二进制流,然后把二进制流反序列化生成一个全新的java对象,即实现了深拷贝。
这种方式需要注意所有的类都需要实现Serializable接口。
1.写一个序列化与反序列化的DeepClone类
DeepClone.java
package com.eric.常用类.object.clone.序列化_深拷贝;

import java.io.*;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 深拷贝-序列化与反序列化
 * @CreateTime 2020-11-27 20:58:09
 */
public class DeepClone implements Serializable {
    private static final long serialVersionUID = 1314521L;
    /**
     * 利用序列化和反序列化进行对象的深拷贝
     * @return
     * @throws Exception
     */
    protected Object deepClone() throws Exception{
        //序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);

        oos.writeObject(this);

        //反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);

        return ois.readObject();
    }
}
2.将Person和Box类都继承DeepClone类以实现深拷贝
Person.java
package com.eric.常用类.object.clone.序列化_深拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 创建person观察浅拷贝的效果
 * @CreateTime 2020-11-27 12:27:20
 */
public class Person extends DeepClone{
    private String name;//名字
    private int age;//年龄
    private Box box;//包裹

    public Person(String name, int age, Box box) {
        this.name = name;
        this.age = age;
        this.box = box;
    }
    
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Box getBox() {
        return box;
    }

    public void setBox(Box box) {
        this.box = box;
    }

    public String disPlay() {
        return "Person[" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", box=" + box +
                ']';
    }
}
Box.java
package com.eric.常用类.object.clone.序列化_深拷贝;

/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 装东西的包裹
 * @CreateTime 2020-11-27 12:30:01
 */
public class Box extends DeepClone{
    private String sa;//物品A
    private String sb;//物品B

    public Box(String sa, String sb) {
        this.sa = sa;
        this.sb = sb;
    }

    public String getSa() {
        return sa;
    }

    public void setSa(String sa) {
        this.sa = sa;
    }

    public String getSb() {
        return sb;
    }

    public void setSb(String sb) {
        this.sb = sb;
    }

    @Override
    public String toString() {
        return "Box[" +
                "sa='" + sa + '\'' +
                ", sb='" + sb + '\'' +
                ']';
    }
}
3测试
package com.eric.常用类.object.clone.序列化_深拷贝;


/**
 * @author Eric
 * @ProjectName my_design_23
 * @description 浅拷贝测试
 * @CreateTime 2020-11-27 12:32:49
 */
public class test {

    public static void main(String[] args) throws Exception {
        Person person = new Person("Eric",22,new Box("时间控制器","免费抽奖机"));
        //克隆
        Person clone = (Person)person.deepClone();

        System.out.println(person);
        System.out.println(clone);

        System.out.println(person.disPlay());
        System.out.println(clone.disPlay());

        clone.setName("喵酱");
        clone.setAge(20);
        Box box = clone.getBox();
        box.setSa("空");
        System.out.println(clone.disPlay());
        System.out.println(person.disPlay());

    }
}
4测试结果
com.eric.常用类.object.clone.序列化_深拷贝.Person@12a3a380
com.eric.常用类.object.clone.序列化_深拷贝.Person@5b480cf9
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
Person[name='喵酱', age=20, box=Box[sa='空', sb='免费抽奖机']]
Person[name='Eric', age=22, box=Box[sa='时间控制器', sb='免费抽奖机']]
从结果来看,已经实现了深拷贝。需要会使用IO相关的知识。




















posted @ 2020-12-29 09:25  喵酱张-Eric  阅读(170)  评论(0编辑  收藏  举报