java 深拷贝和浅拷贝
-
什么是对象拷贝
- 对象拷贝是将一个对象的属性拷贝到另一个有着相同类型的对象中去,主要是在使用中复用当前对象的属性
- 在java中,对象拷贝主要分为三种 深拷贝,浅拷贝,以及延迟拷贝
-
浅拷贝
-
什么是浅拷贝
- 浅拷贝是将对象属性中基本类型的值以及引用类型的地址(String 除过,String在浅拷贝中拷贝的是当前值)复制到新的具有相同属性和相同类型的对象中 (拷贝引用类型只是拷贝属性的地址,如果原对象更改引用类型值,则拷贝对象值随之更改)
-
浅拷贝代码示例如下
/** * 科目类 **/ public class Subject { private String name; public Subject(){} public Subject(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
/** * 学生类 **/ public class Student implements Cloneable{ private String name; private Subject subject; public String getName(){ return name; } public Subject getSubject(){ return subject; } public void setName(String name){ this.name = name; } public void setSubject(Subject subject){ this.subject = subject; } @Override public Object clone(){ Object object = null; try { object = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return object; } }
/** * 测试方法 **/ public static void shallowCopyTest(){ Student student = new Student(); Subject subject = new Subject(); subject.setName("math"); student.setName("zhangyi"); student.setSubject(subject); //copy Student copyStudent = (Student) student.clone(); System.out.println("student 对象复制前后name 内存地址是否相等" + (student.getName() == copyStudent.getName())); System.out.println("student 对象复制前后name 属性值是否相等" + (student.getName().equals(copyStudent.getName()))); System.out.println("student 对象复制前后 subject 内存地址是否相等" + (student.getSubject() == copyStudent.getSubject())); System.out.println("student 对象复制前后 subject 属性值是否相等" + (student.getSubject().getName().equals(copyStudent.getSubject().getName()))); // 修改属性 student.setName("wangyi"); student.getSubject().setName("english"); System.out.println("-----------修改属性后-------------"); System.out.println("student 对象复制前后name 内存地址是否相等" + (student.getName() == copyStudent.getName())); System.out.println("student 对象复制前后name 属性值是否相等" + (student.getName().equals(copyStudent.getName()))); System.out.println("student 对象复制前后 subject 内存地址是否相等" + (student.getSubject() == copyStudent.getSubject())); System.out.println("student 对象复制前后 subject 属性值是否相等" + (student.getSubject().getName().equals(copyStudent.getSubject().getName()))); }
/** * 程序结果显示 **/ student 对象复制前后name 内存地址是否相等true student 对象复制前后name 属性值是否相等true student 对象复制前后 subject 内存地址是否相等true student 对象复制前后 subject 属性值是否相等true -----------修改属性后------------- student 对象复制前后name 内存地址是否相等false student 对象复制前后name 属性值是否相等false student 对象复制前后 subject 内存地址是否相等true student 对象复制前后 subject 属qiankao性值是否相等true
-
浅拷贝总结: 在这个例子中,让拷贝类实现Cloneable 接口,在clone方法中调用super.clone()方法,从输出结果中看到,我们修改原始类name属性,没有影响到拷贝类中name属性,而修改属性Subject类中基本属性,拷贝类中Subject属性也随之改变,即证明了我们上文所说, (拷贝引用类型只是拷贝属性的地址,如果原对象更改引用类型值,则拷贝对象值随之更改)
-
-
深拷贝:
- 什么是深拷贝
- 深拷贝是将对象属性中基本类型的值以及引用类型的值完完全全复制到新的具有相同属性和相同类型的对象中
- 深拷贝代码示例
public class Subject { private String name; public Subject(){} public Subject(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
public class Student implements Cloneable { private String name; private Subject subject; public Student(){} public Student(String name, String subName) { this.name = name; this.subject = new Subject(subName); } public String getName(){ return name; } public Subject getSubject(){ return subject; } public void setName(String name){ this.name = name; } public void setSubject(Subject subject){ this.subject = subject; } @Override public Object clone(){ return new Student(this.name, this.subject.getName()); } }
public static void deepCopyTest(){ com.examplea.algorithm.copy.deep.Student student = new com.examplea.algorithm.copy.deep.Student(); Subject subject = new Subject(); subject.setName("math"); student.setName("zhangyi"); student.setSubject(subject); //copy com.examplea.algorithm.copy.deep.Student copyStudent = (com.examplea.algorithm.copy.deep.Student) student.clone(); System.out.println("student 对象复制前后name 内存地址是否相等" + (student.getName() == copyStudent.getName())); System.out.println("student 对象复制前后name 属性值是否相等" + (student.getName().equals(copyStudent.getName()))); System.out.println("student 对象复制前后 subject 内存地址是否相等" + (student.getSubject() == copyStudent.getSubject())); System.out.println("student 对象复制前后 subject 属性值是否相等" + (student.getSubject().getName().equals(copyStudent.getSubject().getName()))); // 修改属性 student.setName("wangyi"); student.getSubject().setName("english"); System.out.println("-----------修改属性后-------------"); System.out.println("student 对象复制前后name 内存地址是否相等" + (student.getName() == copyStudent.getName())); System.out.println("student 对象复制前后name 属性值是否相等" + (student.getName().equals(copyStudent.getName()))); System.out.println("student 对象复制前后 subject 内存地址是否相等" + (student.getSubject() == copyStudent.getSubject())); System.out.println("student 对象复制前后 subject 属性值是否相等" + (student.getSubject().getName().equals(copyStudent.getSubject().getName()))); }
- 程序输出结果展示
student 对象复制前后name 内存地址是否相等true student 对象复制前后name 属性值是否相等true student 对象复制前后 subject 内存地址是否相等false student 对象复制前后 subject 属性值是否相等true -----------修改属性后------------- student 对象复制前后name 内存地址是否相等false student 对象复制前后name 属性值是否相等false student 对象复制前后 subject 内存地址是否相等false student 对象复制前后 subject 属性值是否相等false
- 深拷贝总结: 在这个例子中,让拷贝类实现Cloneable 接口,在clone方法中重写Object类中clone方法,从输出结果中看到,我们修改原始类name属性,没有影响到拷贝类中name属性,而修改属性Subject类中基本属性,也没有影响到拷贝类型属性Subject类型中基本属性的值,即深拷贝是将对象属性中基本类型的值以及引用类型的值完完全全复制到新的具有相同属性和相同类型的对象中
- 什么是深拷贝
-
延迟拷贝
- 什么是延迟拷贝: 延迟拷贝是浅拷贝和深拷贝的一个组合,当最开始拷贝一个对象时,会使用速度较快的浅拷贝,还会使用一个计数器来记录有多少对象共享这个数据。当程序想要修改原始的对象时,它会决定数据是否被共享(通过检查计数器)并根据需要进行深拷贝