浅拷贝:
浅拷贝(同一个引用):仅仅复制所考虑的对象,而不复制它所引用的对象。
Object类 是所有类的直接或间接父类,Object中存在clone方法,如下
protected native Object clone() throws CloneNotSupportedException;
如果想要使一个类的对象能够调用clone方法 ,则需要实现Cloneable接口, 并重写 clone方法:
package copy; 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; } } class Student2 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 public Object clone() throws CloneNotSupportedException { return super.clone(); } } public class CopyTest { public static void main(String[] args) throws CloneNotSupportedException { Teacher teacher = new Teacher(); teacher.setName("Delacey"); teacher.setAge(29); Student2 student1 = new Student2(); student1.setName("Dream"); student1.setAge(18); student1.setTeacher(teacher); Student2 student2 = (Student2) student1.clone(); System.out.println("拷贝后"); System.out.println(student2.getName());//Dream System.out.println(student2.getAge());//18 System.out.println(student2.getTeacher().getName());//Delacey System.out.println(student2.getTeacher().getAge());//29 System.out.println("修改老师的信息后------"); // 修改老师的信息 teacher.setName("Jam"); System.out.println(student1.getTeacher().getName());//Jam System.out.println(student2.getTeacher().getName());//Jam System.out.println("修改拷贝后的学生信息后与被拷贝学生信息对比------"); student2.setName("MerGy"); System.out.println(student1.getName());//Dream System.out.println(student2.getName());//MerGy } }
深拷贝:
深拷贝会拷贝独立对象所有的属性,并拷贝属性指向的内存。深拷贝会把要复制的对象和引用的对象都拷贝,所以,深拷贝相比于浅拷贝速度较慢并且花销较大。
package copy; class Teacher2 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 public Object clone() throws CloneNotSupportedException { return super.clone(); } } class Student3 implements Cloneable { private String name; private int age; private Teacher2 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 Teacher2 getTeacher() { return teacher; } public void setTeacher(Teacher2 teacher) { this.teacher = teacher; } @Override public Object clone() throws CloneNotSupportedException { // 浅复制时: // return super.clone(); // 改为深复制: Student3 student = (Student3) super.clone(); // 本来是浅复制,现在将Teacher对象复制一份并重新set进来 student.setTeacher((Teacher2) student.getTeacher().clone()); return student; } } public class CopyTest { public static void main(String[] args) throws CloneNotSupportedException { Teacher2 teacher = new Teacher2(); teacher.setName("Delacey"); teacher.setAge(29); Student3 student1 = new Student3(); student1.setName("Dream"); student1.setAge(18); student1.setTeacher(teacher); Student3 student2 = (Student3) student1.clone(); System.out.println("拷贝后"); System.out.println(student2.getName()); System.out.println(student2.getAge()); System.out.println(student2.getTeacher().getName()); System.out.println(student2.getTeacher().getAge()); System.out.println("修改老师的信息后-------------"); // 修改老师的信息 teacher.setName("Jam"); System.out.println(student1.getTeacher().getName());//Jam System.out.println(student2.getTeacher().getName());//Delacey } }
利用序列化实现深拷贝
package blog; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class DeepCopyServiable { public static void main(String[] args) throws Exception { Teacher3 t = new Teacher3(); t.setName("Taylor"); t.setAge(28); Student3 s1 = new Student3(); s1.setAge(20); s1.setName("blank space"); s1.setTeacher(t); Student3 s2 = (Student3) s1.deepClone(); System.out.println("拷贝后:"); System.out.println(s2.getName()); System.out.println(s2.getAge()); System.out.println(s2.getTeacher().getName()); System.out.println(s2.getTeacher().getAge()); System.out.println("---------------------------"); t.setName("swift"); System.out.println("修改后:"); System.out.println(s1.getTeacher().getName()); System.out.println(s2.getTeacher().getName()); } } class Teacher3 implements Serializable { 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; } } class Student3 implements Serializable { private String name; private int age; private Teacher3 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 Teacher3 getTeacher() { return teacher; } public void setTeacher(Teacher3 teacher) { this.teacher = teacher; } public Object deepClone() throws Exception { // 序列化 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); // 反序列化 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } }
重写clone方法 与 通过序列化 两种拷贝方式比较:
clone方法:
优点:速度快,效率高
缺点:在对象引用比较深时,使用此方式比较繁琐
通过序列化:
优点:非常简便的就可以完成深度copy
缺点:由于序列化的过程需要跟磁盘打交道,因此效率会低于clone方式
在java语言中,使用new创建对象与使用clone方法复制一个对象有什么不同?
用new创建对象本意是分配内存。程序到new操作符时,首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这就叫对象的初始化。对象初始化完毕后,可以把引用发布到外部,在外部就可以使用这个引用操纵这个对象。
clone在第一步和new相似,都是分配内存的,调用clone方法时,分配的内存和源对象相同,然后在使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone方法返回,一个新的相同对象就能被创建,同样这个新对象的引用发布到外部。