Java深浅拷贝

浅拷贝:

浅拷贝(同一个引用):仅仅复制所考虑的对象,而不复制它所引用的对象。

Object类 是所有类的直接或间接父类,Object中存在clone方法,如下

protected native Object clone() throws CloneNotSupportedException;

如果想要使一个类的对象能够调用clone方法 ,则需要实现Cloneable接口, 并重写 clone方法:

package copy;

class Teacher implements Cloneable
{
    private String name;
    private int age;

    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;
    }

}

class Student2 implements Cloneable {
    private String name;
    private int age;
    private Teacher teacher;

    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 Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

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

public class CopyTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Teacher teacher = new Teacher();
        teacher.setName("Delacey");
        teacher.setAge(29);

        Student2 student1 = new Student2();
        student1.setName("Dream");
        student1.setAge(18);
        student1.setTeacher(teacher);

        Student2 student2 = (Student2) student1.clone();

        System.out.println("拷贝后");
        System.out.println(student2.getName());//Dream
        System.out.println(student2.getAge());//18
        System.out.println(student2.getTeacher().getName());//Delacey
        System.out.println(student2.getTeacher().getAge());//29

        System.out.println("修改老师的信息后------");
        // 修改老师的信息
        teacher.setName("Jam");
        System.out.println(student1.getTeacher().getName());//Jam
        System.out.println(student2.getTeacher().getName());//Jam

        System.out.println("修改拷贝后的学生信息后与被拷贝学生信息对比------");
        student2.setName("MerGy");
        System.out.println(student1.getName());//Dream
        System.out.println(student2.getName());//MerGy
    }
}

深拷贝:

深拷贝会拷贝独立对象所有的属性,并拷贝属性指向的内存。深拷贝会把要复制的对象和引用的对象都拷贝,所以,深拷贝相比于浅拷贝速度较慢并且花销较大。

package copy;

class Teacher2 implements Cloneable {
    private String name;
    private int age;

    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;
    }

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

class Student3 implements Cloneable {
    private String name;
    private int age;
    private Teacher2 teacher;

    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 Teacher2 getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher2 teacher) {
        this.teacher = teacher;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        // 浅复制时:
        // return super.clone();

        // 改为深复制:
        Student3 student = (Student3) super.clone();
        // 本来是浅复制,现在将Teacher对象复制一份并重新set进来
        student.setTeacher((Teacher2) student.getTeacher().clone());
        return student;
    }

}

public class CopyTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Teacher2 teacher = new Teacher2();
        teacher.setName("Delacey");
        teacher.setAge(29);

        Student3 student1 = new Student3();
        student1.setName("Dream");
        student1.setAge(18);
        student1.setTeacher(teacher);

        Student3 student2 = (Student3) student1.clone();
        System.out.println("拷贝后");
        System.out.println(student2.getName());
        System.out.println(student2.getAge());
        System.out.println(student2.getTeacher().getName());
        System.out.println(student2.getTeacher().getAge());

        System.out.println("修改老师的信息后-------------");
        // 修改老师的信息
        teacher.setName("Jam");
        System.out.println(student1.getTeacher().getName());//Jam
        System.out.println(student2.getTeacher().getName());//Delacey
    }
}

利用序列化实现深拷贝

package blog;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class DeepCopyServiable {
    public static void main(String[] args) throws Exception {
        Teacher3 t = new Teacher3();
        t.setName("Taylor");
        t.setAge(28);

        Student3 s1 = new Student3();
        s1.setAge(20);
        s1.setName("blank space");
        s1.setTeacher(t);

        Student3 s2 = (Student3) s1.deepClone();

        System.out.println("拷贝后:");
        System.out.println(s2.getName());
        System.out.println(s2.getAge());
        System.out.println(s2.getTeacher().getName());
        System.out.println(s2.getTeacher().getAge());
        System.out.println("---------------------------");

        t.setName("swift");

        System.out.println("修改后:");
        System.out.println(s1.getTeacher().getName());
        System.out.println(s2.getTeacher().getName());
    }

}

class Teacher3 implements Serializable
{
    private String name;
    private int age;

    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;
    }

}

class Student3 implements Serializable
{
    private String name;
    private int age;
    private Teacher3 teacher;

    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 Teacher3 getTeacher()
    {
        return teacher;
    }

    public void setTeacher(Teacher3 teacher)
    {
        this.teacher = teacher;
    }

    public 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();
    }

}

重写clone方法 与 通过序列化 两种拷贝方式比较:

clone方法:

优点:速度快,效率高

缺点:在对象引用比较深时,使用此方式比较繁琐

通过序列化:

优点:非常简便的就可以完成深度copy

缺点:由于序列化的过程需要跟磁盘打交道,因此效率会低于clone方式

在java语言中,使用new创建对象与使用clone方法复制一个对象有什么不同?

用new创建对象本意是分配内存。程序到new操作符时,首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这就叫对象的初始化。对象初始化完毕后,可以把引用发布到外部,在外部就可以使用这个引用操纵这个对象。

clone在第一步和new相似,都是分配内存的,调用clone方法时,分配的内存和源对象相同,然后在使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone方法返回,一个新的相同对象就能被创建,同样这个新对象的引用发布到外部。

原文地址:https://www.cnblogs.com/mergy/p/12666511.html