java拷贝--clone

大纲:

  1. java如何拷贝对象。
  2. 浅拷贝
  3. 深拷贝

 

一、java如何拷贝对象

Person p = new Person();
Person p2 = p;

上例并不是一个拷贝操作,只是把p对象的引用赋给了p2,2个变量指向了同一片heap地址。

想实现拷贝操作需要做2件事情:

(1)实现Cloneable接口,这是一个空接口不用重写任何方法。

public interface Cloneable {}

(2)重写clone方法,注意clone方法是Object类中的native方法,并不是Cloneable接口的。

 

二、浅拷贝

改写Person类

@Data
public class Person implements Cloneable {
    private String name;
    private int age;
    private Date birth;

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

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

调用clone方法复制对象:

Person p1 = new Person();
Person p2 = p1.clone();

这样p1,p2就不是一个对象了。

 

三、深拷贝

以上Person对象中的成员变量都是java原生对象和基础数据类型,浅拷贝足以使Person拥有拷贝的功能。

如果为Person加上一个自定类的成员变量

@Data
public class Father {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Father{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Person implements Cloneable {
    private String name;
    private int age;
    private Date birth;
    private Father father;
}

这样做后person中的father对象无法实现拷贝

测试例:

public static void main(String[] args){
        Person p1 = new Person();
        p1.setName("p1");
        Father f1 = new Father();
        f1.setName("f1");
        p1.setFather(f1);
        Person p2 = (Person) p1.clone();
        p2.getFather().setName("f2");
        p2.setName("p2");
        System.out.println(p1);
        System.out.println(p2);

        //结果
        //Person{name='p1', age=0, birth=null, father=Father{name='f2', age=0}}
        //Person{name='p2', age=0, birth=null, father=Father{name='f2', age=0}}
    }

可以看到person对象实现了拷贝,但是father对象还是引用了同一个对象。

 

深拷贝实现步骤:

(1)使自定义的类的成员变量实现Cloneable接口并重写clone方法。

@Data
public class Father implements Cloneable{
    private String name;
    private int age;

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

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

(2)成员变量重写clone方法后,还需要将成员变量的拷贝对象显式赋值。

@Data
public class Person implements Cloneable {
    private String name;
    private int age;
    private Date birth;
    private Father father;

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

    @Override
    public Person clone() {
        Person clone = null;
        try {
            clone = (Person) super.clone();
        } catch (CloneNotSupportedException e) {}
        //这里显式赋值
        if(father!=null){
            clone.setFather(father.clone());
        }
        return clone;
    }
}

 

至此person中的father变量也完成了拷贝,可用上面的测试例子验证一下。

public static void main(String[] args){
    Person p1 = new Person();
    p1.setName("p1");
    Father f1 = new Father();
    f1.setName("f1");
    p1.setFather(f1);
    Person p2 = (Person) p1.clone();
    p2.getFather().setName("f2");
    p2.setName("p2");
    System.out.println(p1);
    System.out.println(p2);
    //结果
    //Person{name='p1', age=0, birth=null, father=Father{name='f1', age=0}}
    //Person{name='p2', age=0, birth=null, father=Father{name='f2', age=0}}
}

 

posted @ 2019-09-12 13:40  扶不起的刘阿斗  阅读(253)  评论(0编辑  收藏  举报