在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
注意:
写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
对象以及对象内部所有引用到的对象都是可序列化的
如果不想序列化,则需要使用transient来修饰
案例:
Teacher:
public class Teacher implements Serializable{ private String name; private int age; private Student student; public Teacher(String name, int age, Student student){ this.name = name; this.age = age; this.student = student; } // 深克隆 public Object deepClone() throws IOException, ClassNotFoundException { // 序列化 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(); } 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 Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; }Student:
public class Student implements Serializable { private String name; private int age; public Student(String name, int age){ this.name = name; this.age = 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; } }client:
public class test { public static void main(String[] args) { try { Student s = new Student("学生1", 11); Teacher origin = new Teacher("老师原对象", 23, s); System.out.println("克隆前的学生姓名:" + origin.getStudent().getName()); Teacher clone = (Teacher) origin.deepClone(); // 更改克隆后的d学生信息 更改了姓名 clone.getStudent().setName("我是克隆对象更改后的学生2"); System.out.println("克隆后的学生姓名:" + clone.getStudent().getName()); }catch (Exception e){ e.printStackTrace(); } } }当然这些工作都有现成的轮子了,借助于Apache Commons可以直接实现:
浅克隆:BeanUtils.cloneBean(Object obj);
深克隆:SerializationUtils.clone(T object);
最后探讨
在java中为什么实现了Cloneable接口,就可以调用Object中的Clone方法
参考以下回答:
https://www.zhihu.com/question/52490586
四:原型模式案例场景如下:新生入学,每个人都要填写自己的个人信息:包括姓名,年龄,身高等等
模板表格:
public class Sheet implements Cloneable { private String name; private int age; private int height; // 初始化个人信息 public Sheet(String name, int age, int height) { this.name = name; this.age = age; this.height = height; } 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 int getHeight() { return height; } public void setHeight(int height) { this.height = height; } // 提供克隆该实例的方法(浅克隆) @Override protected Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } @Override public String toString() { return "Sheet{" + "name='" + name + '\'' + ", age=" + age + ",java">public class Client { public static void main(String[] args) { Sheet sheet = new Sheet("我是模板", 0, 0); Sheet sheet1 = (Sheet) sheet.clone(); sheet1.setName("学生1"); sheet1.setAge(11); sheet1.setHeight(11); System.out.println(sheet1.toString()); Sheet sheet2 = (Sheet) sheet.clone(); sheet2.setName("学生2"); sheet2.setAge(11); sheet2.setHeight(11); System.out.println(sheet2.toString()); } }运行结果:
Sheet{name='学生1', age=11, height=11}
Sheet{name='学生2', age=11, height=11}
优点
如果要创建的对象实例比较复杂,那么用原型模式可以简化其创建过程,减少内存开销,提高效率。
可以使用深克隆的方式保存对象的状态,通过原型模式将其状态保存起来,以便需要时候使用。
缺点
需要为每个类提供克隆方式,极其麻烦,当要扩展克隆方法时候,必须修改源代码,违反开闭原则。
在实现深克隆的时候需要写大量代码,运用起来极其麻烦。
五:使用场景