面向对象之深复制与浅复制

前言:

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

  既然提出来,答案当然是肯定的。“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

 

图二:深复制

posted @ 2015-08-12 21:53  Sea_Sky  阅读(1184)  评论(2编辑  收藏  举报

转载请注明出处! About me