Java--引用拷贝、浅拷贝、深拷贝

  1. 重写clone() 方法时,需要实现 cloneable接口
  2. clone()方法可以实现深拷贝,但当需要克隆的对象中包含引用类型的属性且层级较深时,相关的引用类型都需要实现cloneable接口,且在拷贝的对象中,clone()方法需要做较多的处理,比较麻烦。
  3. 使用序列化来实现深拷贝时,注意涉及到的对象都需要实现序列化接口。对于不需要序列化的属性,使用@transient注解。关键代码中涉及字节数组输入输出流对象输入输出流

测试代码

/**
 * @description:
 * @author: Yuanye.Wong
 * @version: v1.0
 * @data: 2019-06-12 23:56
 **/
public class Demo {

    @Test
    // 引用拷贝
    public void test1(){
        Person p = new Person("小明",20,new Work("coach"));
        Person p2 = p;
        System.out.println("p == p2 : "+(p==p2));
        System.out.println(p);
        System.out.println(p2);
        /*  p == p2 : true
            Person{name='小明', age=20, work=Work(1789447862){name='coach'}}
            Person{name='小明', age=20, work=Work(1789447862){name='coach'}}
        */
    }

    /**
     * 浅拷贝:创建新对象,对原始对象的属性值进行完全拷贝,
     * 属性值是基本类型,则复制值;属性是引用类型,则复制引用(对象的内存地址)。当原始对象中引用类型发生变化,新对象中的属性也随之变化。
     * 实现cloneable接口,使用clone()来实现对象拷贝。当不存在引用类型的属性时,则等同深拷贝,对象间互不影响,存在引用类型的属性时,则为浅拷贝
     */

    // 修改非引用型属性
    @Test
    public void test2() throws CloneNotSupportedException {
        Dog dog1 = new Dog("1aa");
        Dog dog2 = (Dog)dog1.clone();
        System.out.println(dog1 == dog2); // false ,不再是一个对象
        System.out.println(dog2.toString());// Dog{nickName='1aa'}
        dog1.setNickName("1bb");
        System.out.println(dog2.toString());// Dog{nickName='1aa'},原始对象非引用型属性的变化不再影响clone的新对象
    }

    // clone浅拷贝
    @Test
    public void test3() throws CloneNotSupportedException {
        Dog dog1 = new Dog("1aa");
        dog1.setAddress(new Address("SH"));
        Dog dog2 = (Dog)dog1.clone();
        System.out.println(dog1 == dog2); // false ,不再是一个对象
        dog1.setNickName("1bb");
        dog1.getAddress().setZone("BJ");// 浅拷贝的对象中,引用型的属性address指向同一对象,修改address属性,dog1 dog2的address都会随之变化。
        System.out.println(dog1.getNickName()+dog1.getAddress());// 1bbAddress{zone='BJ'}
        System.out.println(dog2.getNickName()+dog2.getAddress());// 1bbAddress{zone='BJ'}
        dog1.setAddress(new Address("CC"));// 将address引用指向新的address对象。 dog1 dog2中的address不再指向同一对象
        System.out.println(dog1.getNickName()+dog1.getAddress());// 1bbAddress{zone='CC'}
        System.out.println(dog2.getNickName()+dog2.getAddress());// 1bbAddress{zone='BJ'}
    }

    // clone 实现深拷贝
    @Test
    public void test4() throws CloneNotSupportedException {
        Person p1 = new Person("mary",20,new Work("coder"));
        Person p2 = (Person) p1.clone();
        System.out.println(p1.toString());
        System.out.println(p2.toString());
        p1.getWork().setName("fighter");
        System.out.println(p1.toString());
        System.out.println(p2.toString());
        /* 结果:
            Person{name='mary', age=20, work=Work(1789447862){name='coder'}}
            Person{name='mary', age=20, work=Work(38997010){name='coder'}}   对比可知,work对象已经不是一个对象了
            Person{name='mary', age=20, work=Work(1789447862){name='fighter'}}  修改引用对象的属性,不再影响新生成的对象,如下
            Person{name='mary', age=20, work=Work(38997010){name='coder'}}
        * */
    }

    // 使用序列化与反序列化进行深拷贝

    /**
     * 关键类:字节数组流、 对象流
     * 拷贝的对象以及对象内引用类型的属性都要实现 Serializable 接口
     */
    @Test
    public void test5(){
        Book book1 = new Book("book1",new Author("mars"));
        Book book2 = null;
        try {
            book2 = (Book)deepCopy(book1);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(book1 == book2);
        book1.getAuthor().setName("tt");
        System.out.println(book1.toString());
        System.out.println(book2.toString());
        /* 结果:
            false
            Book{name='book1', author=Author{name='tt'}}
            Book{name='book1', author=Author{name='mars'}}
        * */
    }

    // 深拷贝:输入输出流处理逻辑
    public Object deepCopy(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.flush();
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        Object result =  ois.readObject();
        oos.close();
        ois.close();
        return result;
    }
}

测试用到的相关类

Work

public class Work implements Cloneable{
    private String name;


    public Work(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

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

    @Override
    public String toString() {
        return "Work("+this.hashCode()+"){" +
                "name='" + name + '\'' +
                '}';
    }
}

Person

public class Person implements Cloneable{
    private String name;
    private int age;
    private Work work;


    public Person(String name, int age, Work work) {
        this.name = name;
        this.age = age;
        this.work = work;
    }

    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 Work getWork() {
        return work;
    }

    public void setWork(Work work) {
        this.work = work;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person p = (Person) super.clone();
        // clone引用类型的值
        p.work = (Work) work.clone();
        return p;
    }

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

Address

public class Address {
    private String zone;

    public Address(String zone) {
        this.zone = zone;
    }

    public String getZone() {
        return zone;
    }

    public void setZone(String zone) {
        this.zone = zone;
    }

    @Override
    public String toString() {
        return "Address{" +
                "zone='" + zone + '\'' +
                '}';
    }
}

Dog

public class Dog implements Cloneable{
    private String nickName;
    private Address address;

    public Dog(String nickName) {
        this.nickName = nickName;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "nickName='" + nickName + '\'' +
                ", address=" + address +
                '}';

    }
}

Author

public class Author  implements Serializable {
    private String name;

    public Author(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

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

Book

public class Book implements Serializable {
    private String name;
    private Author author;

    public Book(String name, Author author) {
        this.name = name;
        this.author = author;
    }

    public String getName() {
        return name;
    }

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

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author=" + author +
                '}';
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章