java中对象的复制分为深克隆与浅克隆
浅克隆:
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深克隆:
与浅克隆相对应的。被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
1.浅克隆:
首先我们来看看Object类中clone方法
protected Object clone()
throws CloneNotSupportedException
-
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象 x,表达式:
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)
按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。
按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。
Object 类的 clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。注意,所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我复制。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。
Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。
-
-
根据上面所说的,浅克隆就是重写Object类得clone方法,重写方法时调用super.clone(),识别出你要调用的哪个对象,同时还需要实现Cloneable接口,查看源代码时可以发现,这个接口没有任何方法,与Serializable一样也是一个标识性的接口。
-
-
2.深克隆:引用类型的实例变量也需要复制一遍,所以我们可以在clone方法中,把引用类型实例变量也按照浅克隆的方法克隆一遍,如果有多个对象,这样显然比较繁琐,这里有一种方法是利用序列化,因为实现序列化的类,其中的引用类型的变量也需要实现序列化,把对象写到流里就是序列化的过程,我们反序列化,把对象从流里读出来,就可以重建对象,实现深克隆。
-
以下是示例代码:
-
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class CloneTest { public static void main(String[] args) throws Exception { Student student = new Student(); Teacher teacher = new Teacher(); teacher.setAge(30); teacher.setName("Miss li"); student.setAge(11); student.setName("zhang san"); student.setTeacher(teacher); Student student2 = (Student) student.deepClone(); System.out.println(student2.getAge()+" "+student2.getName()+" "+student2.getTeacher().getName()); System.out.println("-------------------------------"); teacher.setName("Miss zhao"); System.out.println(student2.getAge()+" "+student2.getName()+" "+student2.getTeacher().getName()); } } class Student implements Cloneable,Serializable{ /** * 序列化ID */ private static final long serialVersionUID = 8566811282124767945L; private int age; private String name; private Teacher teacher; public void setAge(int age) { this.age = age; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } public Teacher getTeacher() { return teacher; } //浅克隆 @Override public Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } //深克隆 public Object deepClone() throws Exception{ //将对象写到流里 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); //从流里读出来 InputStream is = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(is); return ois.readObject(); } } class Teacher implements Serializable{ /** * 序列化ID */ private static final long serialVersionUID = -2380977769309339400L; private int age; private String name; public void setAge(int age) { this.age = age; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public String getName() { return name; } }
-