当前位置:   article > 正文

原型模式之深克隆和浅克隆实现_模仿house案例写一个book类的克隆

模仿house案例写一个book类的克隆

1 什么是原型模式?

原型模式是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

2 为什么要用?

1 如果创建行的对象成本比较大,可以通过复制的方式减少创建的成本。

2 一个类的信息很多,但是又需要一个新的类,新的类和以前的类不同的地方很少,此时可以使用原型模式进行复制操作得到新的对象,再对新对象改变一些信息即可。

3 其他

3 怎么用?

Object类中提供了clone()方法,当简单的重写该方法时,由于该方法是protected的,所以只能是同包下的类才能访问,修饰符可以改成public的,让所有类可以进行克隆操作。

protected native Object clone() throws CloneNotSupportedException;

如果只重写了clone()方法,此时别的类在调用clone()方法,会在运行时出现运行时异常CloneNotSupportedException

克隆类还需要再实现Cloneable接口,这是一个标识接口,实现了这个接口的类JVM才会知道类是支持克隆操作的。

public interface Cloneable {}

 

浅克隆的情况

要进行克隆的类实现Cloneable接口,重写Object类继承来的clone()方法

  1. /**
  2. * 房子类
  3. */
  4. public class House implements Cloneable {
  5. // 住房编号
  6. String roomId;
  7. // 住房面积
  8. int area;
  9. // 房子价值
  10. double price;
  11. // 房主
  12. Person owner;
  13. public House() {
  14. }
  15. public House(String roomId, int area, double price, Person owner) {
  16. this.roomId = roomId;
  17. this.area = area;
  18. this.price = price;
  19. this.owner = owner;
  20. }
  21. @Override
  22. protected Object clone() throws CloneNotSupportedException {
  23. return super.clone();
  24. }
  25. }
  26. /**
  27. * 房主类
  28. */
  29. public class Person implements Cloneable {
  30. // 身份证号
  31. int id;
  32. // 姓名
  33. String name;
  34. public Person() {
  35. }
  36. public Person(int id, String name) {
  37. this.id = id;
  38. this.name = name;
  39. }
  40. @Override
  41. protected Object clone() throws CloneNotSupportedException {
  42. return super.clone();
  43. }
  44. }
  45. /**
  46. * 只支持浅克隆
  47. */
  48. public class Client {
  49. public static void main(String[] args) throws CloneNotSupportedException {
  50. Person MrLiu = new Person(1, "Mr.Liu");
  51. House h1 = new House("1302", 78, 2900, MrLiu);
  52. House h2 = (House) h1.clone();
  53. System.out.println(h1.owner == h2.owner);
  54. }
  55. }

 

h1和h2不是同一个对象,但是h1的owner和h2的owner是同一个对象,表明是浅复制(浅克隆,即对象里的引用对象只拷贝引用,而不拷贝引用指向的对象,基本类型会拷贝)。

 

自定义clone过程实现深克隆

将上面的House类的clone()重写成自己实现克隆

  1. /**
  2. * 嵌套的使用克隆,如果类的对象属性很多,都需要手动编码实现,这个让我很难受。
  3. * @return
  4. */
  5. @Override
  6. protected House clone() {
  7. House house = null;
  8. try {
  9. // 先以浅复制的形式复制house,
  10. // 此时house里的owner属性复制的引用而没有复制对象
  11. house = (House) super.clone();
  12. // 再以浅复制的形式复制owner
  13. house.owner = (Person) house.owner.clone();
  14. } catch (CloneNotSupportedException e) {
  15. e.printStackTrace();
  16. }
  17. return house;
  18. }

 

Debug后可以看出,h1和h2不是同一个对象,h1的owner和h2的owner也不是同一个对象,是深克隆。

 

序列化实现深克隆

此处只给出如何实现验证这个克隆方案,具体如何实现序列化见其他优秀博客,写的很详细。

Serializable也是一个标识接口,表明实现该接口的类可以进行序列化。

public interface Serializable { }

 

这里要注意的是House类实现了序列化,House类里的引用类型也要实现序列化,要不然还是会出现序列化错误。

House类实现序列化,而Person类没有实现序列化接口,运行时报NotSerializableException异常。

  1. /**
  2. * 房子类
  3. */
  4. public class House implements Serializable {
  5. // 住房编号
  6. String roomId;
  7. // 住房面积
  8. int area;
  9. // 房子价值
  10. double price;
  11. // 房主
  12. Person owner;
  13. public House() {
  14. }
  15. public House(String roomId, int area, double price, Person owner) {
  16. this.roomId = roomId;
  17. this.area = area;
  18. this.price = price;
  19. this.owner = owner;
  20. }
  21. }
  22. /**
  23. * 房主类
  24. */
  25. public class Person implements Serializable {
  26. // 身份证号
  27. int id;
  28. // 姓名
  29. String name;
  30. public Person() {
  31. }
  32. public Person(int id, String name) {
  33. this.id = id;
  34. this.name = name;
  35. }
  36. }
  37. /**
  38. * 序列化的方式实现深克隆
  39. */
  40. public class Client {
  41. public static void main(String[] args) throws IOException, ClassNotFoundException {
  42. Person MrLiu = new Person(1, "Mr.Liu");
  43. House h1 = new House("1302", 78, 2900, MrLiu);
  44. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:\\test\\aaa")));
  45. oos.writeObject(h1);
  46. oos.close();
  47. ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:\\test\\aaa")));
  48. House h2 = (House) ois.readObject();
  49. System.out.println(h2);
  50. ois.close();
  51. }
  52. }

 

Debug后可以看出,h1和h2不是同一个对象,h1的owner和h2的owner也不是同一个对象,实现了深克隆。

4 什么时候用?

参考第2条,什么时候要用

5 如何优化?

能力有限,未能深入到这步,请体谅。

6 业务中有其他更好的替代方式吗?

能力有限,未能深入到这步,请体谅。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/68536
推荐阅读
相关标签
  

闽ICP备14008679号