Java中对象的深克隆和浅克隆
2019独角兽企业重金招聘Python工程师标准>>>
浅克隆和深克隆的概念
浅克隆:被克隆的对象里的所有变量值都与原来的对象相同,而所有对其他对象的引用仍然指向原来的对象。简而言之,浅克隆仅仅克隆当前对象,而不克隆当前对象所引用的对象。
深克隆:被克隆的对象里的所有变量值都与原来的对象相同,那些引用其他对象的变量将指向被复制过的新对象,而不再是原来被引用的对象。简而言之,深克隆不仅克隆了当前对象,还把当前对象所引用的对象都复制了一遍。
Java中的clone()方法
Object类中的clone()方法属于浅克隆。它的工作原理是:先在内存中开辟一块和原始对象相同大小的空间,然后原样复制原始对象中的内容。对于基本数据类型,这样操作是没问题的。但对于非基本数据类型,由于它们所保存的仅仅是对象的引用,如果不进行更深层次的克隆,就会导致克隆后的对象引用和原始对象中相应的对象引用所指向的是同一个对象。
使用clone()方法实现浅克隆
在要克隆的类中实现Cloneable接口,覆盖Object类中的clone()方法,并声明为public。同时在clone()方法中,调用super.clone()返回克隆后的对象。请看以下代码:
class Professor {String name;int age;public Professor(String name, int age) {this.name = name;this.age = age;} }class Student implements Cloneable {String name;int age;Professor professor;public Student(String name, int age, Professor professor) {this.name = name;this.age = age;this.professor = professor;}@Overrideprotected Student clone() throws CloneNotSupportedException {return (Student) super.clone();} }public class CloneTutorial {public static void main(String[] args) throws CloneNotSupportedException {Professor professor = new Professor("Galler", 50);Student student1 = new Student("Tom", 18, professor);Student student2 = student1.clone();System.out.println("Before change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("student1's professor age = " + student1.professor.age);student2.professor.name = "Mary";student2.professor.age = 30;System.out.println();System.out.println("After change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("Student1's professor age = " + student1.professor.age);} }
使用clone()方法实现深克隆
通过以上代码可以证明Java中的clone()方法是浅克隆,那应该如何实现更深层次的克隆呢?请看以下代码:
class Professor implements Cloneable {String name;int age;public Professor(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Professor clone() throws CloneNotSupportedException {return (Professor) super.clone();} }class Student implements Cloneable {String name;int age;Professor professor;public Student(String name, int age, Professor professor) {this.name = name;this.age = age;this.professor = professor;}@Overrideprotected Student clone() throws CloneNotSupportedException {Student student = (Student) super.clone();student.professor = student.professor.clone();return student;} }public class CloneTutorial {public static void main(String[] args) throws CloneNotSupportedException {Professor professor = new Professor("Galler", 50);Student student1 = new Student("Tom", 18, professor);Student student2 = student1.clone();System.out.println("Before change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("student1's professor age = " + student1.professor.age);student2.professor.name = "Mary";student2.professor.age = 30;System.out.println();System.out.println("After change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("Student1's professor age = " + student1.professor.age);} }在以上代码中,虽然通过在Student类中调用Professor类中覆盖的clone方法来对professor成员进行克隆从而实现了深克隆,但也由此可见,如果克隆类中的引用类型变量有多个的情况下,采用这种方式实现深克隆将会非常复杂。
使用对象序列化和反序列化实现深克隆(推荐)
把对象写到字节流里的过程是序列化(Serilization)的过程,而把对象从字节流中读出来的过程是反序列化(Deserialization)的过程。由于在Java 序列化的过程中,写在流里的是对象的一个拷贝,而原对象仍然在JVM里,所以可以利用这个原理来实现对对象的深克隆。请看以下代码:
class Professor implements Serializable {String name;int age;public Professor(String name, int age) {this.name = name;this.age = age;} }class Student implements Serializable {String name;int age;Professor professor;public Student(String name, int age, Professor professor) {this.name = name;this.age = age;this.professor = professor;}public Student deepClone() throws Exception {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(this);ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);return (Student) objectInputStream.readObject();} }public class CloneTutorial {public static void main(String[] args) throws Exception {Professor professor = new Professor("Galler", 50);Student student1 = new Student("Tom", 18, professor);Student student2 = student1.deepClone();System.out.println("Before change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("student1's professor age = " + student1.professor.age);student2.professor.name = "Mary";student2.professor.age = 30;System.out.println();System.out.println("After change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("Student1's professor age = " + student1.professor.age);} }
总结
虽然使用Java的clone()方法实现浅克隆以及深克隆更加直观,但是针对每一个需要克隆的类都必须单独实现一个clone()方法,导致其扩展性并不好。而使用对象序列化与反序列化来实现深克隆,能使代码更简洁,更通用。此处推荐使用后者。
转载于:https://my.oschina.net/zhaojia/blog/735432
总结
以上是生活随笔为你收集整理的Java中对象的深克隆和浅克隆的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 【有感而发】
- 下一篇: Java初学者疑难杂症之:一对一和一对多