Java深拷贝和浅拷贝

2020-06-29  本文已影响0人  二狗不是狗

一.等于实现变量赋值

通过等于号实现变量赋值,实际上是把copy变量也指向原来的对象,并没有创建任何新的对象和属性;例如下面的例子我们打印可以看到原来student的hashCode和copy变量的hashCode一致。


image.png
@Data
public class Subject {

    private int subjectId;

    private String subjectNumber;

    private StringBuilder subjectName;
}
@Data
public class Student {

    private int id;

    private String number;

    private StringBuilder name;

    private Subject subject;
}
public static void main(String[] args) {
    Subject subject = new Subject();
    subject.setSubjectId(1);
    subject.setSubjectNumber("aaa");
    subject.setSubjectName(new StringBuilder("aaa"));

    Student student = new Student();
    student.setId(1);
    student.setNumber("aaa");
    student.setName(new StringBuilder("aaa"));
    student.setSubject(subject);

    Student copy = student;

    copy.setId(2);
    copy.setNumber("aaabbb");
    copy.getName().append("bbb");

    copy.getSubject().setSubjectId(2);
    copy.getSubject().setSubjectNumber("aaabbb");
    copy.getSubject().getSubjectName().append("bbb");

    logger.info("student = {}", student.hashCode());
    logger.info("copy = {}", copy.hashCode());

    logger.info("subject = {}", JSON.toJSONString(subject));
    logger.info("student = {}", JSON.toJSONString(student));
}

打印结果为:
student = -859332970
copy = -859332970
subject = {"subjectId":2,"subjectName":"aaabbb","subjectNumber":"aaabbb"}
student = {"id":2,"name":"aaabbb","number":"aaabbb","subject":{"subjectId":2,"subjectName":"aaabbb","subjectNumber":"aaabbb"}}

二.浅拷贝(复制)

  1. 浅拷贝是按位拷贝对象它会创建一个新对象,例如下面的例子我们打印可以看到原来student的hashCode和copy变量的hashCode不一致。
  2. 如果属性是基本类型,拷贝的就是基本类型的值
  3. 如果属性是内存地址(引用类型),拷贝的就是内存地址
  4. 默认拷贝构造函数只是对对象进行浅拷贝复制,即只复制对象空间而不复制资源。
image.png
@Data
public class Subject {

    private int subjectId;

    private String subjectNumber;

    private StringBuilder subjectName;
}
@Data
public class Student implements Cloneable {

    private int id;

    private String number;

    private StringBuilder name;

    private Subject subject;

    @Override
    public Object clone() {
        try {
            Student student = (Student) super.clone();
            return student;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}
public static void main(String[] args) {
    Subject subject = new Subject();
    subject.setSubjectId(1);
    subject.setSubjectNumber("aaa");
    subject.setSubjectName(new StringBuilder("aaa"));

    Student student = new Student();
    student.setId(1);
    student.setNumber("aaa");
    student.setName(new StringBuilder("aaa"));
    student.setSubject(subject);

    Student copy = (Student) student.clone();

    copy.setId(2);
    copy.setNumber("aaabbb");
    copy.getName().append("bbb");

    copy.getSubject().setSubjectId(2);
    copy.getSubject().setSubjectNumber("aaabbb");
    copy.getSubject().getSubjectName().append("bbb");

    logger.info("student = {}", student.hashCode());
    logger.info("copy = {}", copy.hashCode());

    logger.info("subject = {}", JSON.toJSONString(subject));
    logger.info("student = {}", JSON.toJSONString(student));
}

打印结果为:
student = 96321
copy = -1425371071
subject = {"subjectId":2,"subjectName":"aaabbb","subjectNumber":"aaabbb"}
student = {"id":1,"name":"aaabbb","number":"aaa","subject":{"subjectId":2,"subjectName":"aaabbb","subjectNumber":"aaabbb"}}

三.深拷贝(复制)

  1. 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。
  2. 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。
  3. 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。
  4. 深拷贝相比于浅拷贝速度较慢并且花销较大。
  5. 下面的例子因为String类和StringBuilder类没有实现Cloneable接口,所以是浅拷贝
image.png
@Data
public class Subject implements Cloneable {

    private int subjectId;

    private String subjectNumber;

    private StringBuilder subjectName;

    @Override
    public Object clone() {
        try {
            Subject subject = (Subject) super.clone();
            return subject;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}
@Data
public class Student implements Cloneable {

    private int id;

    private String number;

    private StringBuilder name;

    private Subject subject;

    @Override
    public Object clone() {
        try {
            Student student = (Student) super.clone();
            student.setSubject((Subject) subject.clone());
            return student;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}
public static void main(String[] args) {
    Subject subject = new Subject();
    subject.setSubjectId(1);
    subject.setSubjectNumber("aaa");
    subject.setSubjectName(new StringBuilder("aaa"));

    Student student = new Student();
    student.setId(1);
    student.setNumber("aaa");
    student.setName(new StringBuilder("aaa"));
    student.setSubject(subject);

    Student copy = (Student) student.clone();

    copy.setId(2);
    copy.setNumber("aaabbb");
    copy.getName().append("bbb");

    copy.getSubject().setSubjectId(2);
    copy.getSubject().setSubjectNumber("aaabbb");
    copy.getSubject().getSubjectName().append("bbb");

    logger.info("student = {}", student.hashCode());
    logger.info("copy = {}", copy.hashCode());

    logger.info("subject = {}", JSON.toJSONString(subject));
    logger.info("student = {}", JSON.toJSONString(student));
}

打印结果为:
student = 96321
copy = -1425371071
subject = {"subjectId":1,"subjectName":"aaabbb","subjectNumber":"aaa"}
student = {"id":1,"name":"aaabbb","number":"aaa","subject":{"subjectId":1,"subjectName":"aaabbb","subjectNumber":"aaa"}}

上一篇下一篇

猜你喜欢

热点阅读