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