Java 深浅拷贝

Java 深拷贝和浅拷贝

  在浅拷贝中,如果原型对象的成员变量是基本类型时,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

  对应的深拷贝,如果时成员变量为引用对象也复制一份给复制对象。

  

实现

  1、新建一个 Person 和 PersonId 类

public class Person implements Cloneable {

    private String name;
    private int age;
    private PersonId personId;

    public Person(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.personId = new PersonId(id);
    }

    public void setId(int id) {
        personId.setId(id);
    }

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

    public Person clone() throws CloneNotSupportedException {
        Person cloned = (Person)super.clone();
        return cloned;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", personId=" + personId +
                '}';
    }
}
class PersonId{
    private int id;

    public PersonId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "PersonId{" +
                "id=" + id +
                '}';
    }
}

  2、使用 CloneDemo 类来测试浅拷贝

public class CloneDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("zhangsan",20,123);
        Person cloned = person.clone();

        System.out.println("original: "+person);
        System.out.println("cloned: "+cloned);

        System.out.println("Modify Age and Id: ");
        cloned.setAge(55);
        cloned.setId(234);

        System.out.println("original: "+person);
        System.out.println("cloned: "+cloned);
    }
}

  3、输出

Java 深浅拷贝

 

   可以看到我们修改了拷贝对象的年龄和ID,原始对象的年龄还是20,原始对象的ID却变成了我们修改后的值,我们并没有对原始对象的ID进行修改,这里说明浅拷贝对于对象仅仅是拷贝了一个对象的引用而已。

  4、接下来我们修改 Person 类的 clone() 方法,实现深拷贝。

    public Person clone() throws CloneNotSupportedException {
        Person cloned = (Person)super.clone();
        cloned.personId = personId.clone();
        return cloned;
    }

  5、为了拷贝PersonId 的对象我们需要PersonId 类实现 Cloneable 接口

class PersonId implements Cloneable{
    private int id;

    public PersonId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "PersonId{" +
                "id=" + id +
                '}';
    }

    public PersonId clone() throws CloneNotSupportedException {
        return (PersonId)super.clone();
    }
}

  6、再次运行 CloneDemo 输出

Java 深浅拷贝

 

   可以看到 原始对象的ID 值没有被修改。

  7、使用序列化实现深拷贝

import java.io.*;

public class Person implements Cloneable, Serializable {

    private String name;
    private int age;
    private PersonId personId;

    public Person(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.personId = new PersonId(id);
    }

    public void setId(int id) {
        personId.setId(id);
    }

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

    public Person clone() throws CloneNotSupportedException {

        try {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            try(ObjectOutputStream out = new ObjectOutputStream(bout)) {
                out.writeObject(this);
            }

            try(InputStream bin = new ByteArrayInputStream(bout.toByteArray())){
                ObjectInputStream in = new ObjectInputStream(bin);
                return (Person)in.readObject();
            }
        } catch (IOException | ClassNotFoundException e) {
            CloneNotSupportedException e2 = new CloneNotSupportedException();
            e2.initCause(e);
            throw e2;
        }
    }

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

class PersonId implements Cloneable,Serializable{
    private int id;

    public PersonId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "PersonId{" +
                "id=" + id +
                '}';
    }

    public PersonId clone() throws CloneNotSupportedException {
        return (PersonId)super.clone();
    }
}

  所有写入流的对象都要实现 Serializable 接口。将 Person 对象写入流中然后再从流中读取出来实现深拷贝。

   输出:

Java 深浅拷贝

总结

  若要实现深拷贝,如果对象中引用了其他对象,必须将引用的对象也克隆。

  

上一篇:java连接数据库的解决方法大全(mysql)


下一篇:mongodb 安装为windows服务