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 +
                '}';
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章