深入理解Java浅拷贝和深拷贝
首先说一下什么是引用拷贝和对象拷贝。
1. 引用拷贝:
引用拷贝就是创建一个指向对象的引用变量的拷贝,拷贝后生成的对象和原来的对象仍是一个对象,也就是说他们在内存空间中的地址是一样的。
2. 对象拷贝
对象拷贝就是创建对象本身的一个副本,就是在内存空间中开辟一个新的区域存放该对象,这时候就是两个对象了!
深拷贝和浅拷贝都是对象拷贝
1.浅拷贝
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。
简单来说就是只拷贝你考虑的对象,对于内部对象和原来的对象共享。
下面结合代码来看看:
//教师类,是学生类的内部对象
//实现Cloneable接口,默认实现的是浅拷贝
public 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;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//学生类,也是我们要拷贝的“主类”
public class Student 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
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试类:
public class shallowCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setName("liumei");
teacher.setAge(25);
Student student1 = new Student();
student1.setName("mike");
student1.setAge(18);
student1.setTeacher(teacher);
Student student2 = (Student) student1.clone();
//student
System.out.println(student1);
System.out.println(student2);
//teacher
System.out.println(student1.getTeacher());
System.out.println(student2.getTeacher());
}
}
测试结果:
从结果中可以看出,student1和student2是两个对象,而两个学生对象的teacher对象地址却是相同的,这也就印证了我们上边的结论,浅拷贝是不拷贝内部引用的对象的!
2. 深拷贝
深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
简而言之,深拷贝把要复制的对象和引用的对象都复制了一遍。
下面结合代码来看看:
教师类和上述代码一致,我们只看学生类。
public class Student 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;
}
/**
* 深拷贝:不仅赋值主对象,还将内部的对象也重新复制一份
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
//拷贝student对象
Student student = (Student) super.clone();
//拷贝teacher对象,并将其放入拷贝后生成的student对象中
student.setTeacher((Teacher) teacher.clone());
return student;
}
}
测试类与浅拷贝一致,我们直接看结果:
诶? 这次不仅两个学生类的地址不一样了,连内部的teacher类对象的地址也不相同了!
也就是说 深拷贝确实是将内部的引用对象也重新为它开辟空间!
下面看看浅拷贝和深拷贝在内存空间中的图解应该就更能理解了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)