前言:
基于面向对象的思想,大部分的类都可视为“工具”。那么对于工具的使用,我们总是期望能高效而又方便。特别是当我们在重复实现某些功能的时候,那有没有一种能快速复用类的捷径呢?
既然提出来,答案当然是肯定的。“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
图二:深复制