java 深拷贝和浅拷贝

JAVA深拷贝和浅拷贝

参考博客:https://www.jianshu.com/p/94dbef2de298

浅拷贝(shallow Copy)

1.什么是浅拷贝

浅拷贝首先会创建一个新的对象,这个对象和原始对象属性值相同。如果原始对象是数值类型对象,那么拷贝的就是基本类型的值;如果拷贝的对象是引用类型的话,拷贝的就是原始对象的地址,可以说浅拷贝就相当于是一个指针指向被拷贝对象的地址。

2.浅拷贝特点

①对于基础类型的成员对象,浅拷贝会以值传递的方式,直接将属性值赋值给新的对象。修改原始对象的成员或者修改新对象的成员,不会另外一方的值。

②对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响。

3.实现浅拷贝
public class Subject {

    private String name;

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

    public String getName() {
        return name;
    }

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

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

实现浅拷贝对象的类,要实现Cloneable接口

public class Student implements Cloneable {

    private String name;
    //引用类型
    private Subject subject;

    private double score;

    public Student(String name, Subject subject, double score) {
        this.name = name;
        this.subject = subject;
        this.score = score;
    }

    public String getName() {
        return name;
    }

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

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //默认调用父类方法
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", subject=" + subject +
                ", score=" + score +
                '}';
    }
}

测试类

public class ShallowCopy {

    public static void main(String[] args) throws CloneNotSupportedException {
        Subject sub1 = new Subject("math");
        Student stuA = new Student("a", sub1, 77.5);
        Student stuB = (Student) stuA.clone();//拷贝对象
        stuB.setName("b");
        stuB.setScore(88.5);
        stuB.getSubject().setName("science");
        System.out.println(stuA);
        System.out.println(stuB);
    }
}

运行结果

Student{name='a', subject=Subject{name='science'}, score=77.5}
Student{name='b', subject=Subject{name='science'}, score=88.5}

可以看出对新复制出对象的基本数据类型成员进行修改,并不会改变原有对象中的成员,但是对引用类型成员进行修改,则原始对象中的成员也会被改变。

浅拷贝结构图大致如下:

4.关于对象赋值

现在将

Student stuB = (Student) stuA.clone();

修改为

Student stuB = stuA;

可以看到结果

Student{name='b', subject=Subject{name='science'}, score=88.5}
Student{name='b', subject=Subject{name='science'}, score=88.5}

可以看出,对象赋值仅仅是将引用赋值给了新的对象,这两个对象指向同一的内存地址,修改其中一个对象的成员,另一个也会随之修改。

深拷贝(deep Copy)

1.什么是深拷贝

浅拷贝拷贝的对象中的引用类型指向的是同一块堆内存地址。这会使我们修改拷贝对象内容时会有数据安全隐患。深拷贝,在拷贝引用类型成员变量时,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。

2.深拷贝特点

①对于引用类型,深拷贝都会新建一个对象空间来存储这些拷贝的引用,这样就会使它们指向不同的内存地址改变其中一个,不会影响另外一个。

②对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝

③由于得为每一个引用类型成员开辟新的空间,相比较于浅拷贝,深拷贝将会更加消耗内存空间,并且花费更多时间。

3.实现深拷贝

修改subject来,使其也实现Cloneable 并重写 clone()

public class Subject implements Cloneable{

    private String name;

    public Subject(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 "Subject{" +
                "name='" + name + '\'' +
                '}';
    }
}

重写student的clone方法,拷贝引用成员subject

public class Student implements Cloneable {

    private String name;
    //引用类型
    private Subject subject;

    private double score;

    public Student(String name, Subject subject, double score) {
        this.name = name;
        this.subject = subject;
        this.score = score;
    }

    public String getName() {
        return name;
    }

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

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //默认调用父类方法
        Student student = (Student) super.clone();
        student.subject = (Subject) subject.clone();
        return student;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", subject=" + subject +
                ", score=" + score +
                '}';
    }
}

测试类

public class DeepCopy {

    public static void main(String[] args) throws CloneNotSupportedException {
        Subject sub = new Subject("地理");
        Student stuA = new Student("张三", sub, 75.5);
        Student stuB = (Student) stuA.clone();
        stuB.setName("李四");
        stuB.setScore(66.5);
        stuB.getSubject().setName("化学");
        System.out.println(stuA);
        System.out.println(stuB);
    }
}

测试结果

Student{name='张三', subject=Subject{name='地理'}, score=75.5}
Student{name='李四', subject=Subject{name='化学'}, score=66.5}

可以看出,深拷贝后,不管是基础数据类型还是引用类型的成员变量,修改后都不会影响原始对象

深拷贝的结构图大致如下:

posted @ 2021-08-13 16:36  TidalCoast  阅读(59)  评论(0编辑  收藏  举报