zoukankan      html  css  js  c++  java
  • 面向对象之深复制与浅复制

    前言:

      基于面向对象的思想,大部分的类都可视为“工具”。那么对于工具的使用,我们总是期望能高效而又方便。特别是当我们在重复实现某些功能的时候,那有没有一种能快速复用类的捷径呢?

      既然提出来,答案当然是肯定的。“Copy”----复制。

      查看Java中的Object这个祖先类我们可以发现,该类含有一个clone()方法,并且返回“Object”类型。不过,方法的前面还有“native”关键字,其表示Object类使用其方法时是编译器内部执行的,对外界不可正常访问。

      回到正题,什么样的类才可以进行克隆呢?----实现Cloneable接口。常见的Calendar类和Date工具类都已实现了该接口,所以可以直接进行克隆。下面我们自己写一个实现Cloneable接口的类进行测试。

    创建House类及Wall类,其中House类与Wall类属于组合关系。

     1 package clonable;
     2 
     3 public class House implements Cloneable {
     4 
     5     // field
     6 
     7     private int id;
     8     private double area;
     9     private Wall wall;
    10 
    11     public Wall getWall() {
    12         return wall;
    13     }
    14 
    15     public void setWall(Wall wall) {
    16         this.wall = wall;
    17     }
    18 
    19     public double getArea() {
    20         return area;
    21     }
    22 
    23     public House() {
    24         id = 1;
    25         area = 170.5;
    26         wall = new Wall();
    27     }
    28 
    29     public House(double area) {
    30         super();
    31         this.area = area;
    32     }
    33 
    34     public void setArea(double area) {
    35         this.area = area;
    36     }
    37 
    38     public int getId() {
    39         return id;
    40     }
    41 
    42     public void setId(int id) {
    43         this.id = id;
    44     }
    45     /*
    46     @Override
    47     public Object clone() throws CloneNotSupportedException {
    48         House house = (House) super.clone(); // clone self
    49         house.setWall((Wall) house.getWall().clone()); // refresh 'wall' as type
    50                                                         // of Wall
    51         return house;
    52     }
    53     */
    54     @Override
    55     public Object clone() throws CloneNotSupportedException {
    56         return super.clone();
    57     }
    58 
    59     // show the detail message about the house
    60 
    61     public void show() {
    62         System.out.println("area: " + getArea() + ",and the color of wall is:"
    63                 + wall.getColor());
    64 
    65     }
    66 
    67 }
     1 package clonable;
     2 
     3 public class Wall implements Cloneable{
     4     
     5     private String color=null;
     6 
     7     public String getColor(){
     8         return color;
     9     }
    10 
    11     public void setColor(String color) {
    12         this.color = color;
    13     }
    14     
    15     @Override
    16     public Object clone() throws CloneNotSupportedException {
    17         return super.clone();
    18     }
    19     
    20     
    21 }

    测试程序:

     1 package clonable;
     2 
     3 import java.util.Date;
     4 
     5 public class Client {
     6 
     7     public static void main(String[] args) throws Exception{
     8         
     9         
    10         System.out.println("---Clone test!---");
    11         House h1 = new House();
    12         h1.getWall().setColor("Blue");
    13         House h2 = (House)h1.clone();
    14         h2.getWall().setColor("Pink");
    15         House h3 = (House)h1.clone();
    16         h3.getWall().setColor("Black");
    17         
    18         h1.show();
    19         h2.show();
    20         h3.show();
    21     }
    22 
    23 }

    测试结果:

    ---Clone test!---
    area: 170.5,and the color of wall is:Black
    area: 170.5,and the color of wall is:Black
    area: 170.5,and the color of wall is:Black
    

    从结果中我们发现,除了基本类型的值可以进行克隆以外,引用类型无法实现复制。一个set操作,将wall.color属性全部改为black。

    大家看出所以然了麽。其实,这就是所谓的“浅复制(shadow copy)”。其大概意思指的是对实现了Cloneable接口的对象进行克隆的时候,值对象可直接复制,而引用对象只是复制其“引用”而已。所以,才会出现最后的h3的set操作改变了前面h1和h2设置的wall.color属性。具体,可参考下图:

    图一:浅复制

    思考一下,如何实现“深复制”?即在复制基本类型的同时,还能复制引用类型做指向的对象。

    解决方法是这样的,首先得确定引用对象实现了Cloneable接口。然后,我们重写House类的clone()方法对引用对象同样进行克隆操作。最后将其set回house对象,这样便实现了深复制!

    ---修改后的House类----

     1 package clonable;
     2 
     3 public class House implements Cloneable {
     4 
     5     // field
     6 
     7     private int id;
     8     private double area;
     9     private Wall wall;
    10 
    11     public Wall getWall() {
    12         return wall;
    13     }
    14 
    15     public void setWall(Wall wall) {
    16         this.wall = wall;
    17     }
    18 
    19     public double getArea() {
    20         return area;
    21     }
    22 
    23     public House() {
    24         id = 1;
    25         area = 170.5;
    26         wall = new Wall();
    27     }
    28 
    29     public House(double area) {
    30         super();
    31         this.area = area;
    32     }
    33 
    34     public void setArea(double area) {
    35         this.area = area;
    36     }
    37 
    38     public int getId() {
    39         return id;
    40     }
    41 
    42     public void setId(int id) {
    43         this.id = id;
    44     }
    45     
    46     @Override
    47     public Object clone() throws CloneNotSupportedException {
    48         House house = (House) super.clone(); // clone self
    49         house.setWall((Wall) house.getWall().clone()); // refresh 'wall' as type
    50                                                         // of Wall
    51         return house;
    52     }
    53     /*
    54     @Override
    55     public Object clone() throws CloneNotSupportedException {
    56         return super.clone();
    57     }
    58     */
    59     
    60     // show the detail message about the house
    61     public void show() {
    62         System.out.println("area: " + getArea() + ",and the color of wall is:"
    63                 + wall.getColor());
    64 
    65     }
    66 
    67 }

    测试结果:

    ---Clone test!---
    area: 170.5,and the color of wall is:Blue
    area: 170.5,and the color of wall is:Pink
    area: 170.5,and the color of wall is:Black

    图二:深复制

  • 相关阅读:
    Configuration Management
    Android Hooking
    技术趋势总结
    Maven Repo Mirror
    拥抱JAVA
    NPM 更新所有依赖项
    Knockout Mvc Compoment FrameSet With Typescript
    Knockoutjs Component问题汇总
    前端编码规范文档
    优秀程序设计的18大原则
  • 原文地址:https://www.cnblogs.com/SeaSky0606/p/4725678.html
Copyright © 2011-2022 走看看