Java深拷贝和浅拷贝
一.等于实现变量赋值
通过等于号实现变量赋值,实际上是把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"}}
二.浅拷贝(复制)
- 浅拷贝是按位拷贝对象它会创建一个新对象,例如下面的例子我们打印可以看到原来student的hashCode和copy变量的hashCode不一致。
- 如果属性是基本类型,拷贝的就是基本类型的值
- 如果属性是内存地址(引用类型),拷贝的就是内存地址
- 默认拷贝构造函数只是对对象进行浅拷贝复制,即只复制对象空间而不复制资源。
@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"}}
三.深拷贝(复制)
- 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。
- 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。
- 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。
- 深拷贝相比于浅拷贝速度较慢并且花销较大。
- 下面的例子因为String类和StringBuilder类没有实现Cloneable接口,所以是浅拷贝
@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"}}