Java中的深拷贝和浅拷贝
[TOC]
一、什么是深拷贝、浅拷贝
- 浅拷贝:将被复制的对象的成员变量拷贝到新创建的对象的成员变量中,即
- 对于基本类型来说,会直接进行值传递,也就是将该属性值复制一份给新的对象,也就是说新老对象的数据是不共享的,只是值相同而已;
- 对于引用类型来说,拷贝时也是把老对象的引用对象的地址拷贝到新对象中,实际上新老两个对象引用的是用一个对象;
- 深拷贝:不仅对基本类型变量进行值赋值,而且对于引用类型会为新对象创建相应的新的引用类型,即新老对象引用的是不同的对象;
- 示意图:
二、如何实现浅拷贝
- String类型属于引用数据类型,不属于基本数据类型,但是String类型的数据是存放在常量池中的,也就是无法修改的;
2.1通过构造方法实现
-
通过创建一个使用该类对象作为参数的构造方法,能实现浅拷贝;
-
class Student{ public int age; public String name; public Teacher teacher; public Student(int age, String name, Teacher teacher){ this.age=age; this.name=name; this.teacher=teacher; } // 拷贝构造方法 public Student(Student s){ this.age=s.age; this.name=s.name; this.teacher=s.teacher; } } class Teacher{ public int age; public String name; public Teacher(int age, String name){ this.age=age; this.name=name; } } public class ShallowCopy { public static void main(String[] args) { Teacher t1 = new Teacher(30,"zyn"); Student s1 = new Student(20,"kevin",t1); Student s2 = new Student(s1); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); s1.age=25; s1.name="kevin11"; s1.teacher.age=40; System.out.println("修改s1的name、age、teacher后"); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); } }
-
运行结果:
s1是kevin, 20,s1的老师为 zyn, 30 s2是kevin, 20,s2的老师为 zyn, 30 修改s1的name、age、teacher后 s1是kevin11, 25,s1的老师为 zyn, 40 s2是kevin, 20,s2的老师为 zyn, 40
2.2重写Object中的clone方法实现
-
在Object类中有一个方法为clone()就是用来进行浅拷贝的,使用时需要注意:
- 在Object类中,该方法是protected的,重写时要改为public;
- 使用clone方法的类必须要实现Cloneable接口;
-
代码:
class Student implements Cloneable{ public int age; public String name; public Teacher teacher; public Student(int age, String name, Teacher teacher){ this.age=age; this.name=name; this.teacher=teacher; } @Override public Object clone(){ Object obj = null; try{ obj = super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return obj; } } class Teacher{ public int age; public String name; public Teacher(int age, String name){ this.age=age; this.name=name; } } public class ShallowCopy { public static void main(String[] args) throws CloneNotSupportedException { Teacher t1 = new Teacher(30,"zyn"); Student s1 = new Student(20,"kevin",t1); Student s2 = (Student) s1.clone(); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); s1.age=25; s1.name="kevin11"; s1.teacher.age=40; System.out.println("修改s1的name、age、teacher后"); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); } }
-
运行结果:
s1是kevin, 20,s1的老师为 zyn, 30 s2是kevin, 20,s2的老师为 zyn, 30 修改s1的name、age、teacher后 s1是kevin11, 25,s1的老师为 zyn, 40 s2是kevin, 20,s2的老师为 zyn, 40
三、如何实现深拷贝
3.1重写Object中的clone方法实现
-
基本思路和浅拷贝的思路差不多,主要是要对每个引用对象创建相应的对象;
-
代码:
class Student implements Cloneable{ public int age; public String name; public Teacher teacher; public Student(int age, String name, Teacher teacher){ this.age=age; this.name=name; this.teacher=teacher; } @Override public Object clone(){ Object obj = null; try{ obj = super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } Student s = (Student)obj; s.teacher = (Teacher)this.teacher.clone(); return obj; } } class Teacher implements Cloneable{ public int age; public String name; public Teacher(int age, String name){ this.age=age; this.name=name; } @Override public Object clone(){ Object obj = null; try{ obj = super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return obj; } } public class DeepCopy { public static void main(String[] args) throws CloneNotSupportedException { Teacher t1 = new Teacher(30,"zyn"); Student s1 = new Student(20,"kevin",t1); Student s2 = (Student) s1.clone(); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); s1.age=25; s1.name="kevin11"; s1.teacher.age=40; System.out.println("修改s1的name、age、teacher后"); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); } }
-
运行结果:
s1是kevin, 20,s1的老师为 zyn, 30 s2是kevin, 20,s2的老师为 zyn, 30 修改s1的name、age、teacher后 s1是kevin11, 25,s1的老师为 zyn, 40 s2是kevin, 20,s2的老师为 zyn, 30
3.2通过序列化和反序列化来实现
-
进行序列化时要将对象加入流中,该过程就是对象的深拷贝,原对象任在JVM运行时数据区域中,再通过反序列化从流中读取数据,可以获得新的拷贝对象
- 进行序列化的类要实现Serializable接口
-
代码:
import java.io.*; public class DeepCopyBySerialization { public static void main(String[] args) throws IOException, ClassNotFoundException { Teacher t1 = new Teacher(30,"zyn"); Student s1 = new Student(20,"kevin",t1); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(s1); oos.flush(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); Student s2 = (Student) ois.readObject(); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); s1.age=25; s1.name="kevin11"; s1.teacher.age=40; System.out.println("修改s1的name、age、teacher后"); System.out.println("s1是"+s1.name+", "+s1.age+",s1的老师为 "+s1.teacher.name+", "+s1.teacher.age); System.out.println("s2是"+s2.name+", "+s2.age+",s2的老师为 "+s2.teacher.name+", "+s2.teacher.age); } } class Student implements Serializable { public int age; public String name; public Teacher teacher; public Student(int age, String name, Teacher teacher){ this.age=age; this.name=name; this.teacher=teacher; } } class Teacher implements Serializable{ public int age; public String name; public Teacher(int age, String name){ this.age=age; this.name=name; } }
-
运行结果:
s1是kevin, 20,s1的老师为 zyn, 30 s2是kevin, 20,s2的老师为 zyn, 30 修改s1的name、age、teacher后 s1是kevin11, 25,s1的老师为 zyn, 40 s2是kevin, 20,s2的老师为 zyn, 30