浅拷贝和深拷贝
参考资料:
4.1 什么是浅拷贝?什么是深拷贝?
- 浅拷贝:浅拷贝是创建一个新对象,这个对象有着原始属性值的一份精确拷贝,如果是基本数据类型,拷贝的就是基本数据类型的值,如果是深拷贝,拷贝的就是内存地址。所以如果浅拷贝的对象或者对象本身改变了属性或者值那么也会影响另一个对象
- 深拷贝:深拷贝是将这个对象完整的拷贝下来,从内存空间中开辟一个新的地址来存放这个新对象,所以深拷贝创建的对象在改变值之后不会对另一个对象产生影响
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
4.2 赋值和深拷贝,浅拷贝的区别?
- 赋值:当我们把一个对象赋值给另一个变量引用时,会把这个对象在栈内存中的地址给这个变量引用,这两个对象使用 == 进行比较返回true,这个情况下,不管哪个对象发生改变,改变的都是存储空间中同一块内存地址的数据,所以他们是联动的,不管改变哪个对象,另外一个对象的数据也会跟着改变。
浅克隆代码演示
准备实体类对象,并创建对应的get set 有参数构造和无参数构造并实现Cloneable接口中的clone方法
- 创建学生实体类
public class Student implements Cloneable{ private int sid; private String sname; private Teacher teacher; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
- 创建老师实体类
public class Teacher implements Cloneable{ private Integer tid; private String tname; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
创建测试类Main
public class Main { public static void main(String[] args) throws CloneNotSupportedException { // 创建老师对象 Teacher teacher = new Teacher(); teacher.setTid(1); teacher.setTname("张老师"); // 学生对象 Student student = new Student(); student.setSid(1); student.setSname("小明同学"); student.setTeacher(teacher); // 创建学生的克隆对象 浅克隆 Student cloneStudent = (Student) student.clone(); System.out.println("浅克隆=》比较源对象和克隆对象 " + (student == cloneStudent)); System.out.println("浅克隆=》查询修改前源对象:" + student); System.out.println("浅克隆=》查询修改前克隆对象:" + cloneStudent); System.out.println("修改源对象中学生的sid属性为 2"); student.setSid(2); System.out.println("修改源对象中学生的sname属性为 小红同学"); student.setSname("小红同学"); System.out.println("修改源对象中学生的teacher属性中的tid属性为 2"); student.getTeacher().setTid(2); System.out.println("浅克隆=》查询修改后源对象:" + student); System.out.println("浅克隆=》查询修改后克隆对象:" + cloneStudent); } }
输出结果
浅克隆=》比较源对象和克隆对象 false 浅克隆=》查询修改前源对象:Student(sid=1, sname=小明同学, teacher=Teacher(tid=1, tname=张老师)) 浅克隆=》查询修改前克隆对象:Student(sid=1, sname=小明同学, teacher=Teacher(tid=1, tname=张老师)) 修改源对象中学生的sid属性为 2 修改源对象中学生的sname属性为 小红同学 修改源对象中学生的teacher属性中的tid属性为 2 浅克隆=》查询修改后源对象:Student(sid=2, sname=小红同学, teacher=Teacher(tid=2, tname=张老师)) 浅克隆=》查询修改后克隆对象:Student(sid=1, sname=小明同学, teacher=Teacher(tid=2, tname=张老师))
浅克隆总结
浅拷贝:拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深克隆代码演示
深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
- 创建学生实体类
public class Student implements Cloneable{ private int sid; private String sname; private Teacher teacher; @Override protected Object clone() throws CloneNotSupportedException { return new Student(sid,sname,new Teacher(teacher.getTid(),teacher.getTname())); } }
- 创建老师实体类
public class Teacher implements Cloneable{ private Integer tid; private String tname; @Override protected Object clone() throws CloneNotSupportedException { return new Teacher(tid,this.tname); } }
- 创建测试类
public class Main2 { public static void main(String[] args) throws CloneNotSupportedException { // 创建老师对象 Teacher teacher = new Teacher(); teacher.setTid(1); teacher.setTname("张老师"); // 学生对象 Student student = new Student(); student.setSid(1); student.setSname("小明同学"); student.setTeacher(teacher); // 创建学生的克隆对象 浅克隆 Student cloneStudent = (Student) student.clone(); System.out.println("深克隆=》比较源对象和克隆对象 " + (student == cloneStudent)); System.out.println("深克隆=》比较源对象和克隆对象的自定义引用数据类型 " + (student.getTeacher() == cloneStudent.getTeacher())); System.out.println("深克隆=》查询修改前源对象:" + student); System.out.println("深克隆=》查询修改前克隆对象:" + cloneStudent); System.out.println("修改源对象中学生的sid属性为 2"); student.setSid(2); System.out.println("修改源对象中学生的sname属性为 小红同学"); student.setSname("小红同学"); System.out.println("修改源对象中学生的teacher属性中的tid属性为 2"); student.getTeacher().setTid(2); System.out.println("深克隆=》查询修改后源对象:" + student); System.out.println("深克隆=》查询修改后克隆对象:" + cloneStudent); } }
输出结果
深克隆=》比较源对象和克隆对象 false 深克隆=》比较源对象和克隆对象的自定义引用数据类型 false 深克隆=》查询修改前源对象:Student(sid=1, sname=小明同学, teacher=Teacher(tid=1, tname=张老师)) 深克隆=》查询修改前克隆对象:Student(sid=1, sname=小明同学, teacher=Teacher(tid=1, tname=张老师)) 修改源对象中学生的sid属性为 2 修改源对象中学生的sname属性为 小红同学 修改源对象中学生的teacher属性中的tid属性为 2 深克隆=》查询修改后源对象:Student(sid=2, sname=小红同学, teacher=Teacher(tid=2, tname=张老师))
### 深克隆总结
深拷贝:深拷贝会创建一个新的对象,将源对象的属性值放入到新对象,是创建对象赋值,并不是将引用地址指向原来的对象,所以我们在上面测试代码中可以发现深拷贝后的Teacher对象中的源对象和克隆对象比较时返回false,当一个值做更改的时候也不会影响另外一个对象