- 浅拷贝:只拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
或者说,被复制对象的所有变量都含有与原来的对象相同的值,对象的引用对象会在原来的对象和它的副本之间共享。 调用clone()得到的对象。
- 深拷贝:不仅拷贝对象本身,而且拷贝对象包含引用指向的所有对象。
简而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。即对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容。override clone()得到的对象,
对其内的引用类型的变量,再进行一次 clone()。或者使用序列化。
范例:
对象A1中包含对B1的引用,B1中包含对C1的引用。
浅拷贝A1得到A2,A2中依然包含对B1的引用,B1中依然包含对C1的引用。
深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2中包含对C2(C1的copy)的引用。
范例:浅拷贝
1.实体类 - Professor0
1 public class Professor0 implements Cloneable { 2 3 public String name; 4 5 public int age; 6 7 public Professor0(String name, int age) { 8 this.name = name; 9 this.age = age; 10 } 11 12 public Object clone() throws CloneNotSupportedException { 13 return super.clone(); 14 } 15 16 17 18 }
2.实体类 - Student0
1 public class Student0 implements Cloneable { 2 3 public String name; 4 public int age; 5 public Professor0 p; 6 public Student0(String name, int age, Professor0 p) { 7 this.name = name; 8 this.age = age; 9 this.p = p; 10 } 11 12 public Object clone() { 13 Student0 o = null; 14 try { 15 o = (Student0) super.clone(); 16 } catch (CloneNotSupportedException e) { 17 System.out.println(e.toString()); 18 } 19 return o; 20 } 21 22 23 24 25 }
3.浅拷贝类 - ShallowCopy
1 public class ShallowCopy { 2 3 public static void main(String[] args) { 4 Professor0 p = new Professor0("张三", 50); 5 Student0 s1 = new Student0("李四", 18, p); 6 Student0 s2 = (Student0) s1.clone(); 7 s2.p.name = "王五"; 8 s2.p.age = 30; 9 s2.name = "赵六"; 10 s2.age = 45; 11 System.out.println("学生s1的姓名:" + s1.name + " 学生s1教授的姓名:" + s1.p.name + ", 学生s1教授的年龄:" + s1.p.age); 12 } 13 14 }
结果: 学生s1的姓名:李四
学生s1教授的姓名:王五,
学生s1教授的年龄:30
总结:s2.p变了,s1.p也变了,证明s1的p和s2的p指向的是同一个对象
范例:深拷贝
1.实体类 - Professor
1 public class Professor implements Cloneable { 2 3 public String name; 4 5 public int age; 6 7 public Professor(String name, int age) { 8 this.name = name; 9 this.age = age; 10 } 11 12 public Object clone(){ 13 Object o = null; 14 try { 15 o = super.clone(); 16 } catch (CloneNotSupportedException e) { 17 System.out.println(e.toString()); 18 } 19 return o; 20 } 21 22 23 24 }
2.实体类 - Student
1 public class Student implements Cloneable { 2 3 public String name; 4 public int age; 5 public Professor p; 6 public Student(String name, int age, Professor p) { 7 this.name = name; 8 this.age = age; 9 this.p = p; 10 } 11 12 public Object clone() { 13 Student o = null; 14 try { 15 o = (Student) super.clone(); 16 } catch (CloneNotSupportedException e) { 17 System.out.println(e.toString()); 18 } 19 o.p = (Professor) p.clone(); 20 return o; 21 } 22 23 24 25 26 }
3.深拷贝类 - DeepCopy
1 public class DeepCopy { 2 3 public static void main(String[] args) { 4 5 long t1 = System.currentTimeMillis(); 6 Professor p = new Professor("张三", 50); 7 Student s1 = new Student("李四", 18, p); 8 Student s2 = (Student) s1.clone(); 9 s2.p.name = "王五"; 10 s2.p.age = 30; 11 System.out.println("学生s1的姓名:" + s1.name + " 学生s1教授的姓名:" + s1.p.name + ", 学生s1教授的年龄:" + s1.p.age); 12 long t2 = System.currentTimeMillis(); 13 System.out.println(t2-t1); 14 } 15 16 }
结果: 学生s1的姓名:李四
学生s1教授的姓名:张三,
学生s1教授的年龄:50
1
总结:s2.p变了,s1.p没变。证明s1的p和s2的p指向的不是同一个对象
范例:采用序列化实现深拷贝
1.实体类 - Professor2
1 public class Professor2 implements Serializable { 2 private static final long serialVersionUID = 1L; 3 4 public String name; 5 6 public int age; 7 8 public Professor2(String name, int age) { 9 this.name = name; 10 this.age = age; 11 } 12 13 14 }
2.实体类 - Student2
1 public class Student2 implements Serializable { 2 private static final long serialVersionUID = 1L; 3 public String name; 4 public int age; 5 public Professor2 p; 6 7 public Student2(String name, int age, Professor2 p) { 8 this.name = name; 9 this.age = age; 10 this.p = p; 11 } 12 13 public Object deepClone() throws IOException, ClassNotFoundException { 14 // 将对象写到流里 15 ByteArrayOutputStream bo = new ByteArrayOutputStream(); 16 ObjectOutputStream oo = new ObjectOutputStream(bo); 17 oo.writeObject(this); 18 // 从流里读出来 19 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); 20 ObjectInputStream oi = new ObjectInputStream(bi); 21 return oi.readObject(); 22 23 } 24 25 }
3.深拷贝类 - DeepCopy2
1 public class DeepCopy2 { 2 3 public static void main(String[] args) throws ClassNotFoundException, IOException { 4 5 long t1 = System.currentTimeMillis(); 6 Professor2 p = new Professor2("张三", 50); 7 Student2 s1 = new Student2("李四", 18, p); 8 Student2 s2 = (Student2) s1.deepClone(); 9 s2.p.name = "王五"; 10 s2.p.age = 30; 11 System.out.println("学生s1的姓名:" + s1.name + " 学生s1教授的姓名:" + s1.p.name + ", 学生s1教授的年龄:" + s1.p.age); 12 long t2 = System.currentTimeMillis(); 13 System.out.println(t2-t1); 14 } 15 16 }
结果: 学生s1的姓名:李四
学生s1教授的姓名:张三,
学生s1教授的年龄:50
85
总结:s2.p变了,s1.p没变。证明s1的p和s2的p指向的不是同一个对象。相比实现Cloneable,实现Serializable更耗时。